更好地理解序言
我试图了解 Prolog 以及它如何使用解析算法。我有这个例子,我发现:
hates(1, 2).
hates(2, 3).
hates(3, 4).
jealous(A, B) :- jealous(A, C), jealous(C,B).
jealous(A,B) :- hates(A,B).
但是当我试图说jealous(1,4)然后它不断溢出并且永远不会产生真时,这很奇怪,好像1讨厌2,2讨厌3,3讨厌4,那么1也应该讨厌4。
但是我尝试改变它,所以它是这样的:
hates(1, 2).
hates(2, 3).
hates(3, 4).
jealous(A,B) :- hates(A,B).
jealous(A, B) :- jealous(A, C), jealous(C,B).
然后当我说jealous(1,4).
回答
然后当我说的时候它就起作用了
jealous(1,4)
不,它没有。或者,嗯,有点。只需键入SPACE以查看它是否再次循环。又是怎么回事jealous(4,1)这立即循环?
要理解这一点,只需查看程序的一小部分就足够了,即:
嫉妒(A,B): -错误,讨厌(A,B)。 嫉妒(A,B): - 嫉妒(A,C),假,嫉妒(C,B)。
注意B在可见部分从未使用过的变量。所以它不会对终止产生任何影响。并注意A哪个刚刚交给第一个目标。所以这两个参数在这个程序中都没有影响。因此这个程序永远不会终止。它可能会在这里和那里找到解决方案,但是当被要求找到所有解决方案时,它永远不会终止。
这个小片段称为失败切片,如果它没有终止,那么你的整个程序也会终止!也就是说,没有必要读你的定义,hates/2在所有1。
如果您想掌握 Prolog 的执行,您需要掌握失败切片的概念。因为,有经验的程序员或多或少是凭直觉做到这一点的。因此,他们不会阅读整个程序,他们只是扫描相关部分。Prolog 中的好处是这样的切片和整个程序之间存在真正的因果关系。
要解决此问题,您需要更改故障切片突出显示的部分中的某些内容。这是一种可能的变化:
jealous(A,B) :- false, hates(A,B). jealous(A, B) :- jealous(A, C), false,jealous(C,B).
但是一旦你有了循环hates/2,这将不再有效。然后,考虑closure/3:
jealous(A,B) :- hates(A,B).
jealous(A, B) :- hates(A, C), jealous(C,B).
另一种方法是使用表格。但请注意,制表解决了这一问题,但在约束环境中将不再起作用(您迟早会遇到这种情况)。
1) 前提是你有一个纯单调的程序。