逻辑处理列表

时间:2010-10-30 18:28:44

标签: list prolog prolog-findall

我的程序中有大量的事实,列出了公司的开发人员和设计人员,以及之前的项目,如此......

% 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)轻松完成这项工作,但我不确定如何使用员工列表来完成此操作。有人能帮我一把吗?

2 个答案:

答案 0 :(得分:1)

请考虑以下内容,它不依赖于findallsetofbagof等所有解决方案内置函数:

% 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找不到尚未积累的东西,我们在那时寻找更多;直到没有更多,在这种情况下我们停止(第二个条款是基本情况)。

虽然相对于findallsetofbagof的任何内部(即本机,非解释)实现,这可能效率低下,但它可用于演示一种预期的方法帮助您使用累加器方法了解解决方案。

如果您需要使用内置的全解决方案,则可以实现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).

请注意,setofbagof会回溯给您提供替代方案,但您希望累积列表中的所有项目,这是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集合交集谓词intersection/3,它会使列表没有重复(因此使用sort/2构造employee_projects/2中的输入列表{1}})。

答案 1 :(得分:0)

尝试与此类似的内容,其中Es是员工列表:

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

E^是一个存在量词。