質問
私のプログラム内には多くの事実があり、会社の開発者とデザイナーをリストし、以前のプロジェクトなど。
% 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).
また、プロジェクトに取り組んでいるデザイナーまたは開発者のリストを表示する定義も作成しました
% employees(Single Project, List of Employees
employees(Project, E)
私が望むのは、デザイナーまたは開発者のいずれかのリストを取得し、両方とも取り組んできたすべてのプロジェクトタイトルのリスト(P)を表示する新しい定義を作成することです。そのようです..
% projects_of_all(List of Staff, List of Projects)
projects_of_all(S,P):- ...
一人の人の映画を見つけなければならない場合、Findall(またはBagof)で簡単にこれを行うことができますが、従業員のリストでこれをどのように行うかはわかりません。誰かが私にこれで助けてくれますか?
解決
次のことを考えてみましょう。 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
経由で取得されます designer/3
また developer/3
(選択ポイントを離れる)、新しいまで Project
まだ蓄積されていないことが見つかりません。その時点で、私たちはもっと探しに行きます。これ以上ないまで、その場合は停止します(2番目の句は基本ケースです)。
これはおそらく、内部(すなわち、ネイティブ、非解釈されていない)の実装に比べて非効率的です 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-prologセットインターセクションの述語に依存しています intersection/3
, 、重複していないリストを取得します(したがって、 sort/2
入力リストを作成します employee_projects/2
).
他のヒント
これに似たものを試してみてください Es
従業員のリストです:
setof(P, E^(member(E, Es), employee(P, E)), Projects)
E^
実存的な量子です。