prolog:修复多个答案(使用剪切?)

时间:2009-12-17 21:15:48

标签: prolog

我正在计算列表中的实例数量......

count(_,[],N,N).
count(Elem,[Elem|List],N,M) :- !, N1 is N+1, count(Elem,List,N1,M). 
count(Elem,[_|List],N,M) :- count(Elem,List,N,M). 

所以,我在prolog中写了两个方法,第一个工作(上面),但我很想知道为什么第二个没有(或者更确切地说,会给我多个答案 - 只有第一个是正确的这是为什么?

非常感谢

count(Z,X,R) :- count2(Z,X,R,0).
count2(W,[H|T],L,A):- (W == H), Lnew is A+1, count2(W,T,L,Lnew).
count2(W,[H|T],L,A):- count2(W,T,L,A).
count2(W,[],A,A).

3 个答案:

答案 0 :(得分:2)

第二次尝试产生多个解决方案的原因是第二个count2子句不会阻止W和H采用相同的值。因此,即使count2的第一个子句成功,它也可以回溯并在第二个子句上再次成功。

你可以通过使用剪切来解决这个问题,正如Vincent Ramdhanie所说,或者如果你更愿意避免使用剪切,你可以在第二个句子中添加一个明确的检查,以防止W和H统一,如下所示: / p>

count(Z,X,R) :- count2(Z,X,R,0).
count2(W,[W|T],L,A):- Lnew is A+1, count2(W,T,L,Lnew).
count2(W,[H|T],L,A):- W \= H, count2(W,T,L,A).
count2(_,[],A,A).

另请注意,第一个count2子句现在使用隐式统一。而不是一个明确的检查。在我看来,这有点短,更容易阅读。当然,除非你有使用平等而不是统一的原因。

答案 1 :(得分:0)

你的问题包括答案......削减。剪切总是成功并且具有“切断”派生树的副作用。基本上你不能回溯通过削减。

如果目标与第二个规则统一,第一个示例将执行剪切。从某种意义上说,这种选择是固定的。如果失败或回溯之后它没有阻止切割,从而消除了多个答案。当答案相互排斥时,剪切很有用。也就是说,当你找到第一个答案时,没有其他人会有意义。

答案 2 :(得分:-1)

得到了它!

这是一个有效的解决方案:

count(Z,X,R) :- count2(Z,X,R,0).
count2(W,[H|T],L,A):- (W == H), !, Lnew is A+1, count2(W,T,L,Lnew).
count2(W,[H|T],L,A):- count2(W,T,L,A).
count2(W,[],A,A).

谢谢文森特 - 你让我重温了剪辑!