Domanda

Ho un gran numero di fatti nel mio programma, messa in vendita di sviluppatori e designer in una società, così come i progetti precedenti, in questo modo ..

% 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).

Ho anche costruire una definizione che visualizza un elenco di entrambi i progettisti o gli sviluppatori che lavorano su un progetto

% employees(Single Project, List of Employees
employees(Project, E)

Quello che voglio è quello di creare una nuova definizione che prende un elenco di entrambi i progettisti o gli sviluppatori e visualizza un elenco di tutti i titoli del progetto che hanno entrambi lavorato su (P); in questo modo ..

% projects_of_all(List of Staff, List of Projects)
projects_of_all(S,P):- ...

I può farlo facilmente con findall (o bagof) se devo trovare il film di una sola persona, ma io non sono sicuro di come avrei fatto questo con un elenco dei dipendenti. Qualcuno può darmi una mano con questo?

È stato utile?

Soluzione

Si consideri il seguente che non si basa sui tutti-solutions built-in come findall, setof o 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).

Questa versione si accumula una lista unica di dipendenti che lavorano su un progetto. Allo stesso modo, l'implementazione del vostro projects_of_all/2 predicato può essere in quanto tale:

% 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). 

Si noti la \+ var(Employees) guardia sotto-obiettivo, come non vogliamo che entrambi gli argomenti per la chiamata a member(Employee, Employees) per essere completamente non legato, che può causare una dilatazione infinitamente ricorsiva di variabili nelle liste di sempre maggiore lunghezza. Una volta che selezioniamo un Employee, qualsiasi Project associato viene recuperato tramite designer/3 o developer/3 (lasciando choicepoints), finché non viene trovato un nuovo Project non ancora accumulato, momento in cui andiamo alla ricerca di più; fino a quando non ci sono più, nel qual caso ci fermiamo (il 2 ° clausola è il caso base).

Mentre questo è probabilmente inefficiente relativa a un qualsiasi interno (cioè, nativo, non interpretato) attuazione di findall, setof o bagof, serve a dimostrare un approccio che ha lo scopo di aiutarvi a capire la soluzione utilizzando metodi di accumulo.

Se si richiede l'utilizzo di un all-soluzioni integrate, è possibile implementare projects_of_all/2 come tale:

% 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).

Si noti che setof e bagof potranno tornare indietro per dare alternative, ma si desidera che tutti i progetti in un elenco accumulato, che è il comportamento di findall. Presumibilmente, però, non si vuole duplicati, così chiamando sort/2 sul risultato, come mostrato elimina i doppioni per darvi un set.

Modifica Il PO cambiato (chiarificato) la questione dopo che avevo scritto questo, che chiedeva una risposta completamente diversa (spiegazione di seguito):

% 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 viene utilizzato per costruire una lista di elenchi di progetti che ogni Employee nella lista di input aveva lavorato. Nota che usa la strategia di soluzione findall/3 ho usato in precedenza. Il secondo predicato, recursive_val_intersect/2,3, determina l'intersezione di tutti gli elenchi di progetti, in quanto questo indica i progetti che ogni dipendente ha lavorato insieme . Questo è diverso per la soluzione di cui sopra che cerca solo tutti i progetti lavorato da tutti i dipendenti nella lista di input, che è quello che avevo mirato a.

Si noti che recursive_val_intersect/3 sopra si basa sulla SWI-PROLOG set-intersezione predicato intersection/3 , che prende elenchi senza duplicazioni (quindi l'uso di sort/2 per costruire le liste di input in employee_projects/2).

Altri suggerimenti

Prova qualcosa di simile a questo, in cui Es l'elenco dei dipendenti:

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

Il E^ è un quantificatore esistenziale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top