findall
、setof
またはのような組み込みのすべてのソリューションに依存しない次のことを検討してください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).
このバージョンは、プロジェクトに取り組んでいる従業員の一意のリストを蓄積します。同様に、述語の実装は次のprojects_of_all/2
ようになります。
% 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).
\+ var(Employees)
呼び出しに対する両方の引数が完全にバインドされていないことを望まないため 、ガードサブゴールに注意してくださいmember(Employee, Employees)
。これにより、長さが増加し続けるリスト内の変数が無限に再帰的に展開される可能性があります。を選択すると、まだ蓄積されていない新しいものが見つかるまで、または(選択ポイントを残して)を介してEmployee
関連するProject
ものが取得されます。それ以上なくなるまで、その場合は停止します(2番目の節が基本ケースです)。designer/3
developer/3
Project
findall
これは、、setof
またはの内部(つまり、ネイティブ、非解釈)実装に比べておそらく非効率的ですがbagof
、アキュムレータメソッドを使用してソリューションを理解するのに役立つことを目的としたアプローチを示すのに役立ちます。
組み込みのすべてのソリューションを使用する必要がある場合は、次のように実装できますprojects_of_all/2
。
% 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).
setof
とは代替案を提供するためにバックトラックすることに注意してください。ただしbagof
、リスト内のすべてのプロジェクトを累積する必要があります。これは、の動作ですfindall
。ただし、おそらく、重複は望ましくないのでsort/2
、示されているように結果を呼び出すと、重複が削除されてセットが得られます。
編集:私がこれを書いた後、OPは質問を変更(明確化)しました、それは完全に異なる答えを要求しました(以下の説明):
% 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
Employee
入力リストのそれぞれが作業したプロジェクトのリストのリストを作成するために使用されます。findall/3
以前に使用したソリューション戦略を使用していることに注意してください。2番目の述語はrecursive_val_intersect/2,3
、すべてのプロジェクトリストの共通部分を決定します。これは、すべての従業員が一緒に取り組んだプロジェクトを示しているためです。これは、入力リスト内のすべての従業員が取り組んでいるすべてのプロジェクトを検索する上記のソリューションとは異なります。これは、私が目指していたものです。
recursive_val_intersect/3
上記はSWI-PROLOGset-intersection述語に依存していることに注意してくださいintersection/3
。これは、重複のないリストを取得します(したがって、を使用しsort/2
て入力リストを作成しますemployee_projects/2
)。