2016-09-29 5 views
2

У меня есть предикат, называемый пауком со следующим кодом:Пролог предикат возвращает только один результат

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. 

Звонки на паук (ADA), паук (BEDA) и паук (калла) все отдельно возвращает истину. Но когда я называю пауком (X), я не получаю все три решения для X. Я просто получаю первое решение, то есть X = ada. Я не понимаю, почему, потому что человек (X) гарантирует, что я получу все три возможных значения X, чтобы запустить остальную часть предиката. Вызов паука (X) в режиме трассировки не показывает никаких очевидных объяснений, но мой компилятор SWI-Prolog просто игнорирует другие случаи. Почему не все три решения печатаются при вызове паука (X)?

ответ

0

Причина вышеуказанного поведения - это сокращения, которые вы используете в предикате паука/1. Если вы удалите их и написать:

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

тогда, если вы запрашиваете:

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

Это дает все решения через возвратов, но он дает правильные решения более чем один раз. Этого нельзя избежать, используя! потому что он также отрежет некоторые правильные ответы. Чтобы сохранить правильные решения только один раз вы могли бы написать еще один предикат:

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

Теперь, если вы запрашиваете:

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

Это дает правильные решения только один раз.

+0

Вы также можете использовать ['setof/3'] (http://www.swi-prolog.org/pldoc/doc_for?object=setof/3) вместо' findall/3' + 'sort/2' , – user3389669