Question

J'ai un grand nombre de faits dans mon programme, la liste des développeurs et des concepteurs dans une entreprise, ainsi que des projets précédents, comme si ..

% 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).

J'ai aussi construire une définition qui affiche une liste de concepteurs soit ou développeurs travaillant sur un projet

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

Ce que je veux est de créer une nouvelle définition qui prennent une liste de designers ou développeurs soit et affiche une liste de tous les titres du projet, ils ont tous deux travaillé sur (P); comme si ..

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

Je peux le faire facilement avec findall (ou bagof) si je dois trouver les films d'une seule personne, mais je ne sais pas comment je ferais cela avec une liste des employés. Quelqu'un peut-il me donner un coup de main avec cela?

Était-ce utile?

La solution

Considérez ce qui suit, qui ne repose pas sur les solutions tout-Encastrements comme findall, setof ou 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).

Cette version accumule une liste unique des employés travaillant sur un projet. De même, la mise en œuvre de votre projects_of_all/2 sous-jacente peut être en tant que tel:

% 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). 

Notez la subgoal de garde \+ var(Employees), comme nous ne voulons pas que les deux arguments à l'appel à member(Employee, Employees) pour être complètement libre, qui peut provoquer une expansion infinie récursive des variables dans les listes de longueur de plus en plus. Une fois que nous choisissons un Employee, tout Project associé est récupéré via designer/3 ou developer/3 (en laissant choicepoints), jusqu'à ce qu'un nouveau Project pas encore accumulé se trouve, à laquelle nous aller chercher plus; jusqu'à ce qu'il n'y a pas de plus, dans ce cas, nous nous arrêtons (la 2ème clause est le cas de base).

Bien que ce soit probablement inefficace par rapport à toute mise en œuvre de findall, setof ou bagof interne (c.-à-native, non interprété), elle sert à démontrer une approche qui vise à vous aider à comprendre en utilisant des méthodes d'accumulateur la solution.

Si vous avez besoin l'utilisation d'un vous pouvez toutes les solutions-intégrées, mettre en œuvre projects_of_all/2 en tant que tel:

% 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).

Notez que setof et bagof vont revenir en arrière pour vous donner des solutions de rechange, mais vous voulez tous les projets dans une liste accumulée, qui est le comportement de findall. On peut supposer, cependant, vous ne voulez pas les doublons, afin d'appeler sort/2 sur le résultat comme indiqué Enlève les doublons pour vous donner un ensemble.

EDIT: OP changé (clarifié) la question après avoir écrit ce qui demandait une réponse complètement différente (explication ci-dessous):

% 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 est utilisé pour construire une liste de listes de projets que chaque Employee dans la liste d'entrée avait travaillé. Notez qu'il utilise la stratégie de solution findall/3 je plus tôt. Le second prédicat, recursive_val_intersect/2,3, détermine l'intersection de toutes les listes de projets, comme cela indique les projets que chaque employé a travaillé ensemble . Ceci est différent à la solution ci-dessus qui vise simplement tous les projets ont travaillé sur tous les employés dans la liste d'entrée, ce qui est ce que j'avais visé.

Notez que recursive_val_intersect/3 ci-dessus repose sur l'ensemble intersection SWI-Prolog prédicat intersection/3, qui prend des listes sans doubles (d'où l'utilisation de sort/2 pour construire des listes d'entrée en employee_projects/2).

Autres conseils

Essayez quelque chose de similaire à celui-ci où Es la liste des employés:

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

Le E^ est un quantificateur existentiel.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top