2016-09-29 4 views
2

J'ai un prédicat appelé araignée avec le code suivant:prédicat Prolog retourne un seul résultat

person(ada). 
person(beda). 
person(calle). 
knows(ada,beda). 
knows(ada,calle). 
knows(beda,calle). 

% Returns true for arguments X and Y if either knows(X,Y) or knows(Y,X) is true. 
xknowsy(X,Y) :- knows(X,Y). 
xknowsy(X,Y) :- knows(Y,X). 

subsetsof([],[]). 
subsetsof([A|B],[A|D]) :- subsetsof(B,D). 
subsetsof([A|B],D) :- subsetsof(B,D). 

dontknowlist([]). 
dontknowlist([A]). 
dontknowlist([A,B|C]) :- not(xknowsy(A,B)), dontknowlist([A|C]), dontknowlist([B|C]). 

listknowsconspirator([],C). 
listknowsconspirator([A|B],C) :- knowssomeone(A,C), listknowsconspirator(B,C). 

knowssomeone(A,[]). 
knowssomeone(A,[B|C]) :- xknowsy(A,B). 
knowssomeone(A,[B,C|D]) :- knowssomeone(A,[C|D]). 

spider(X) :- person(X), findall(A,xknowsy(X,A),B), subsetsof(B,C), dontknowlist(C),!, 
findall(E,person(E),F), removespider(F,X,G), removeconspirators(G,C,L),!, 
listknowsconspirator(L,C),!. 

removespider([],X,L) :- L = []. 
removespider([A|B],X,L) :- A = X, L = B. 
removespider([A|B],X,L) :- not(A = X), removespider(B,X,M), L = [A|M]. 

removeconspirators([],D,L) :- L = []. 
removeconspirators(E,[],L) :- L = E. 
removeconspirators([A],[B],L) :- A = B, L = []. 
removeconspirators([A],[B],L) :- not(A = B), L = [A]. 
removeconspirators([A,B|C],[D],L) :- A = D, L = [B|C]. 
removeconspirators([A,B|C],[D],L) :- not(A = D), removeconspirators([B|C],[D],M), L = [A|M]. 
removeconspirators([A|B],[S,T|U],L) :- removeconspirators([A|B],[S],M), 
removeconspirators(M,[T|U],N), L = N. 

appels à l'araignée (ada), araignée (Beda) et araignée (rue) tout retour séparément vrai. Mais quand j'appelle spider (X), je n'ai pas les trois solutions pour X. Je viens d'obtenir la première solution, c'est-à-dire X = ada. Je ne comprends pas pourquoi parce que personne (X) s'assure que j'obtiens les trois valeurs X possibles pour exécuter le reste du prédicat. Appeler spider (X) en mode trace ne semble pas révéler d'explications évidentes, mais mon compilateur SWI-Prolog semble simplement ignorer les autres cas. Pourquoi les trois solutions ne sont-elles pas imprimées lors de l'appel de spider (X)?

Répondre

0

La raison du comportement ci-dessus est les coupes que vous utilisez dans le prédicat spider/1. Si vous les supprimez et écrivez:

spider(X) :- person(X), findall(A,xknowsy(X,A),B), subsetsof(B,C),dontknowlist(C), 
findall(E,person(E),F), removespider(F,X,G), removeconspirators(G,C,L), 
listknowsconspirator(L,C). 

alors si vous recherchez:

?- final_spider(X). 
X = ada ; 
X = ada ; 
X = ada ; 
X = beda ; 
X = beda ; 
X = beda ; 
X = calle ; 
X = calle ; 
X = calle. 

Cela donne toutes les solutions par retours en arrière, mais il donne les bonnes solutions plus d'un temps. Ce n'est pas facile à éviter en utilisant! parce que ça va aussi couper quelques bonnes réponses. Pour garder des solutions droite une seule fois, vous pouvez écrire un autre prédicat:

final_spider(X):-findall(Y,spider(Y),L),sort(L,L1),member(X,L1). 

Maintenant, si vous recherchez:

?- final_spider(X). 
X = ada ; 
X = beda ; 
X = calle. 

Il donne les bonnes solutions qu'une seule fois.

+0

Vous pouvez également utiliser ['setof/3'] (http://www.swi-prolog.org/pldoc/doc_for?object=setof/3) au lieu de' findall/3' + 'sort/2' . – user3389669