2

我的程序中有大量事实,列出公司中的开发人员和设计师,以及以前的项目,像这样..

% 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)轻松完成此操作,但我不确定如何使用员工列表执行此操作。有人可以帮我解决这个问题吗?

4

2 回答 2

1

考虑以下不依赖于所有解决方案的内置插件,如findall,setofbagof

% 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 or developer/3(留下选择点)检索,直到Project找到一个尚未累积的新的,此时我们去寻找更多;直到不再有,在这种情况下我们停止(第二个子句是基本情况)。

findall虽然这可能相对于, setofor的任何内部(即本机,非解释)实现而言效率低下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).

请注意,setofandbagof将回溯为您提供替代方案,但您希望累积列表中的所有项目,这是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我之前使用的解决方案策略。第二个谓词recursive_val_intersect/2,3确定所有项目列表的交集,因为这表示每个员工一起工作的项目。这与上述解决方案不同,后者仅在输入列表中查找所有员工从事的所有项目,这正是我的目标。

请注意,recursive_val_intersect/3上面依赖于 SWI-PROLOG set-intersection predicate intersection/3,它接受没有重复的列表(因此使用sort/2来构造输入列表employee_projects/2)。

于 2010-11-02T01:05:24.780 回答
0

尝试类似的事情,Es员工列表在哪里:

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

E^一个存在量词。

于 2010-10-30T19:05:03.100 回答