Pregunta

Tengo un gran número de hechos dentro de mi programa, enumerando los desarrolladores y diseñadores en una empresa, así como los proyectos anteriores, como así ..

% project(Project Name,Year)
project(efnet, 2007).
% designer(Project Name, Name, Role)
designer(efnet, jane_cole, lead).
% developer(Project Name, Name, Role)
developer(efnet, alex_tobbs, architect).

También he construir una definición que muestra una lista de cualquiera de los diseñadores o desarrolladores que trabajan en un proyecto

% employees(Single Project, List of Employees
employees(Project, E)

Lo que quiero es crear una nueva definición que tome una lista de cualquiera de los diseñadores o desarrolladores y muestra una lista de todos los títulos de los proyectos que ambos han trabajado en (P); al igual que ..

% projects_of_all(List of Staff, List of Projects)
projects_of_all(S,P):- ...

Me puede hacer esto fácilmente con findall (o bagof) si tengo que encontrar las películas de una sola persona, pero no estoy seguro de cómo me gustaría hacer esto con una lista de los empleados. Alguien me puede dar una mano con esto?

¿Fue útil?

Solución

Tenga en cuenta lo siguiente, que no se basa en las soluciones todo-muebles empotrados como findall, setof o bagof:

% employees(Single Project, List of Employees
employees(Project, Employees) :-
    employees(Project, [], Employees).

employees(Project, Acc, Employees) :-
    (   designer(Project, Employee, _)
    ;   developer(Project, Employee, _)
    ),
    \+ member(Employee, Acc), !,
    employees(Project, [Employee|Acc], Employees).
employees(_Project, Employees, Employees).

Esta versión se acumula una lista única de los empleados que trabajan en un proyecto. Del mismo modo, la implementación de su projects_of_all/2 predicado puede ser como tal:

% projects_of_all(List of Staff, List of Projects)
projects_of_all(Employees, Projects):- 
    projects_of_all(Employees, [], Projects).

projects_of_all(Employees, Acc, Projects):-
    \+ var(Employees),
    member(Employee, Employees),
    (   designer(Project, Employee, _)
    ;   developer(Project, Employee, _)
    ),
    \+ member(Project, Acc), !,
    projects_of_all(Employees, [Project|Acc], Projects).
projects_of_all(_Employees, Projects, Projects). 

Tenga en cuenta el \+ var(Employees) guardia sub-objetivo, ya que no queremos que los dos argumentos de la llamada a member(Employee, Employees) ser completamente sin consolidar, lo que puede causar una expansión infinitamente recursiva de las variables en las listas de cada vez mayor longitud. Una vez que seleccionamos un Employee, cualquier Project asociado se recuperará a través de designer/3 o developer/3 (dejando choicepoints), hasta que se encuentre un nuevo Project aún no acumulada, momento en el que vamos en busca de más; hasta que no hay más, en cuyo caso nos detenemos (la segunda cláusula es el caso base).

Si bien esto es probablemente ineficaz en relación con cualquier interna (es decir, nativo, no interpretado) la aplicación de findall, setof o bagof, sirve para demostrar un enfoque que está destinada a ayudar a entender la solución utilizando métodos acumulador.

Si usted requiere el uso de un todo-soluciones integradas, que podría poner en práctica projects_of_all/2 tales como:

% projects_of_all(List of Staff, List of Projects)
projects_of_all(Employees, Projects):- 
    findall(Project, 
        (   member(Employee, Employees), 
            (   designer(Project, Employee, _)
            ;   developer(Project, Employee, _)
            )
        ), ProjectsBag),
    sort(ProjectsBag, Projects).

Tenga en cuenta que setof y se bagof dar marcha atrás para darle alternativas, pero desea que todos los proyectos en una lista acumulada, que es el comportamiento de findall. Es de suponer que, sin embargo, no desea duplicados, así que llamar sort/2 en el resultado como se muestra Elimina duplicados para darle un conjunto.

EDIT: El PO cambiado (clarificada) la cuestión después de haber escrito esto, que pidió una respuesta completamente diferente (la explicación más abajo):

% projects_of_all(List of Staff, List of Projects)
projects_of_all(Employees, CommonProjects):- 
    % find the projects of every employee in the input list
    employee_projects(Employees, EmployeeProjects),
    % find the intersection of all projects (common projects)
    recursive_val_intersect(EmployeeProjects, CommonProjects).

employee_projects([], []).
employee_projects([Employee|Employees], [Projects|Rem]) :-
    findall(Project, 
        (   designer(Project, Employee, _)
        ;   developer(Project, Employee, _)
        ),
    ProjectsBag),
    sort(ProjectsBag, Projects),
    employee_projects(Employees, Rem).

recursive_val_intersect([L|Ls], Intersect) :-
    recursive_val_intersect(Ls, L, Intersect).
recursive_val_intersect([], Acc, Acc).
recursive_val_intersect([L0|Ls], L1, Intersect) :-
    intersection(L0, L1, NewL),
    recursive_val_intersect(Ls, NewL, Intersect).

employee_projects/2 se utiliza para crear una lista de listas de proyectos que cada Employee en la lista de entrada había trabajado. Tenga en cuenta que se utiliza la estrategia de solución findall/3 he usado antes. El segundo predicado, recursive_val_intersect/2,3, determina la intersección de todas las listas de proyectos, ya que esto indica que los proyectos que cada empleado tiene trabajado juntos . Esto es diferente a la anterior solución que acaba busca todos los proyectos trabajados por todos los empleados en la lista de entrada, que es lo que había tenido como objetivo.

Tenga en cuenta que recursive_val_intersect/3 anterior se basa en la SWI-Prolog puesta a punto de intersección predicado intersection/3, que toma listas sin duplicados (de ahí el uso de sort/2 para construir las listas de entrada en employee_projects/2).

Otros consejos

Prueba algo similar a este, donde Es es la lista de los empleados:

setof(P, E^(member(E, Es), employee(P, E)), Projects)

El E^ es un cuantificador existencial.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top