Frage

Ich habe eine große Anzahl von Fakten in meinem Programm, Listing-Entwickler und Designer in einem Unternehmen sowie frühere Projekte, wie so ..

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

Ich habe bauen auch eine Definition, dass zeigt eine Liste von entweder Designer oder Entwickler an einem Projekt arbeiten

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

Was ich will, ist eine neue Definition zu erstellen, die eine Liste von entweder Designer nehmen oder Entwickler und zeigt eine Liste aller Projekttitel sie beide gearbeitet haben (P); wie so ..

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

Das kann ich leicht mit findall (oder bagof), wenn ich die Filme von einer einzigen Person zu finden, aber ich bin nicht sicher, wie ich das von den Mitarbeitern mit einer Liste tun würde. Kann mir jemand mit diesem eine helfende Hand geben?

War es hilfreich?

Lösung

Betrachten Sie die folgenden, die lässt sich nicht verlassen, um die all-Lösungen Einbauten wie findall, setof oder 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).

Diese Version sammelt sich eine eindeutige Liste der Mitarbeiter an einem Projekt arbeiten. In ähnlicher Weise kann die Umsetzung Ihres Prädikat projects_of_all/2 als solche sein:

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

Beachten Sie die Wache subgoal \+ var(Employees), da wir völlig ungebunden sein, nicht beiden Argumente für den Aufruf member(Employee, Employees) mögen, welche eine unendlich rekursive Erweiterung von Variablen in Listen der immer größer werdende Länge führen kann. Sobald wir einen Employee wählen, alle zugehörigen Project über designer/3 abgerufen oder developer/3 (Abfahrt Choicepoints), bis ein neuer Project noch nicht angehäuft gefunden wird, zu welcher Zeit wir gehen der Suche nach mehr; bis es nicht mehr, in diesem Fall werden wir (die zweite Klausel ist der Basisfall) stoppen.

Während dies wahrscheinlich ineffizient relativ zu internen (dh nativen, nicht interpretiert) Umsetzung von findall, setof oder bagof, es dient dazu, einen Ansatz zu demonstrieren, die zu Hilfe soll verstehen Sie die Lösung Speicher Methoden verwenden.

Wenn Sie die Verwendung eines All-Lösungen integrierten in benötigen, könnten Sie projects_of_all/2 als solche implementieren:

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

Beachten Sie, dass setof und bagof wird Rückzieher Sie Alternativen zu geben, aber Sie alle Projekte in einer Liste angesammelt, die das Verhalten von findall ist. Vermutlich aber wollen Sie nicht Duplikate, so sort/2 auf das Ergebnis Aufruf als entfernt Duplikate angezeigt Sie einen Satz zu geben.

EDIT: Die OP geändert (geklärte) die Frage, nachdem ich dies geschrieben hatte, die für eine völlig andere Antwort genannt (Erklärung unten):

% 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 wird verwendet, um eine Liste von Listen von Projekten zu bauen, dass jeder Employee in der Eingabeliste gearbeitet hatte. Beachten Sie, dass es verwendet die findall/3 Lösung Strategie, die ich früher verwendet. Das zweite Prädikat, recursive_val_intersect/2,3, bestimmt den Schnittpunkt aller Projektlisten, da dies die Projekte zeigt, dass jeder Mitarbeiter hat gearbeitet zusammen . Dies unterscheidet sich von der obigen Lösung, die nur alle Projekte von allen Mitarbeitern in der Eingabeliste bearbeitet sucht, das ist, was ich angestrebt hatte.

Beachten Sie, dass recursive_val_intersect/3 verlässt sich oben auf der SWI-Prolog-Set-Kreuzung Prädikat intersection/3 , die Listen ohne Duplikate (daher die Verwendung von sort/2 der Eingangslisten in employee_projects/2 zu konstruieren) hat.

Andere Tipps

Versuchen Sie, etwas ähnlich wie diese, wo Es die Liste der Mitarbeiter:

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

Die E^ ist ein Existenzquantor.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top