这两个步骤之间的区别是什么?
1)
find(X,[X|Tail]).
find(X,[Head|Tail]):-find(X,Tail).
2)
find(X,[X|Tail]):-!.
find(X,[Head|Tail]):-find(X,Tail).
答案 0 :(得分:2)
当Prolog执行查询时,它会寻找查找成功查询的所有解决方案(true)。在一个非常简单的例子中,如果我有:
foo(a).
foo(b).
我输入:
| ?- foo(X).
X = a ? ;
X = b
yes
你可以看到Prolog找到两个解决方案,然后停止。这里发生的是,在Prolog找到解决方案X = a
并按;
后,您要求Prolog找到更多解决方案。 Prolog然后回溯到最近遇到的“选择点”(查询执行中的点,它决定选择有效的替代选择)并尝试另一个选择。在这种情况下,它会找到foo(b)
并匹配foo(X)
,因此您也会获得X = b
。 Prolog在找到X = b
后没有更多的选择点,因此在提示X = b
之后它没有选择,只是说yes
(它在最后一次成功)。
Prolog cut(!
)用于消除选择点。或者说另一种方式,它告诉Prolog,在此之前不要回溯。
现在让我们简单介绍一下:
foo(a) :- !.
foo(b).
然后查询变为:
| ?- foo(X).
X = a
yes
在Prolog找到解决方案X = a
之后,剪切已经消除了回溯。
在使用find/2
的给定示例中,如果我们使用非剪切版本执行查询find(b, [a,b,c]).
,我们会得到:
| ?- find(b, [a,b,c]).
true ? ;
no
如果我们对剪切版本做同样的事情,我们会得到:
| ?- find(b, [a,b,c]).
yes
嗯。他们都成功找到b
但结果看起来有点不同。在第一种情况下,Prolog在b
中找到[a,b,c]
,当它最终遇到该子句时,find(X, [X|_]).
但是没有削减,所以这里有一个选择点,因为还有以下子句,{{ 1}}。 Prolog说,find(X, [_|Tail) :-...
并询问您是否要回溯以找到更多解决方案(返回选择点)。由于它无法从该选择点找到另一种解决方案,因此它最终说“不”。
在第二种情况下,Prolog通过条款true ?
找到第一个解决方案(成功),但是切割消除了选择点并告诉Prolog,如果你到了这里,不要打扰允许回溯到从这一点开始的任何其他解决方案。因此,您只需获得“成功”,Prolog就会停止寻找更多解决方案。
当只有一个解决方案时,剪切只会删除不必要的回溯以找到更多不存在的解决方案。但是,如果有多个解决方案可用,那么削减将阻止Prolog回溯并找到其中一些解决方案。
这是另一个简单的例子,说明了剪辑可以做的“修剪解决方案”:
find(X, [X|_]) :- !.
然后查询:
a(1). a(2).
b(1). b(2).
foo(X, Y) :- a(X), b(Y).
介绍剪辑:
| ?- foo(X, Y).
X = 1
Y = 1 ? a
X = 1
Y = 2
X = 2
Y = 1
X = 2
Y = 2
yes
| ?-
然后查询:
foo(X, Y) :- a(X), !, b(Y).
在这种情况下发生的事情是切断阻止回溯以在子句中找到| ?- foo(X, Y).
X = 1
Y = 1 ? a
X = 1
Y = 2
yes
| ?-
的附加选项。但是在为a(X)
寻找解决方案时仍然有一个选择点,我们并没有削减它们。如果我们按照以下b(Y)
进行了切割,那么那些也会被切断:
b(Y)
然后它只会找到一个解决方案:
foo(X, Y) :- a(X), b(Y), !.
许多Prolog书籍都有一些关于削减的讨论。一个很好的是,Clocksin& amp;&amp ;; Mellish。它有图表等,显示了切割和选择点的工作方式。