Вопрос

У меня есть большое количество фактов в моей программе, листит разработчиков и дизайнеров в компании, а также предыдущие проекты, как и так ..

% 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 В результате, как показано, удаляет дубликаты, чтобы дать вам набор.

РЕДАКТИРОВАТЬ: ОП изменился (уточненный) вопрос после того, как я написал это, который призвал совершенно другой ответ (объяснение ниже):

% 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/3, который принимает списки без дубликатов (следовательно, использование sort/2 Чтобы построить входные списки в employee_projects/2).

Другие советы

Попробуйте что-то подобное на это, где Es это список сотрудников:

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

То E^ это экзистенциальный квантов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top