为什么Prolog在这个简单的例子中会崩溃?

4
likes(tom,jerry).
likes(mary,john).
likes(mary,mary).
likes(tom,mouse).
likes(jerry,jerry).
likes(jerry,cheese).
likes(mary,fruit).
likes(john,book).
likes(mary,book).
likes(tom,john).

likes(john,X):-likes(X,john), X\=john.

你好,上面是一个非常简单的Prolog文件,包含一些事实和只有一个规则:John喜欢任何喜欢他的人。

但是在加载了这个文件并向Prolog查询以下内容后:

likes(john,X).

程序崩溃了。原因是Prolog在likes(john,john)处卡住了,即使规则表明X\=john。有什么建议吗?

好奇一下,如果X=john在likes之前出现会发生什么? - pedrofurla
很奇怪,如果你把它放在主体前面,Prolog会返回: X = book ; false. 我不知道为什么它停在了 book 后面。 - Max
2个回答

3

讽刺的是,鉴于我们所在的网站,您正在遇到堆栈溢出。

这是因为prolog使用的执行顺序,它将在您的规则中的likes(X,john)处进入无限递归,它激活了规则而不是事实,永远不会到达X\=john部分。

修复此问题的一种方法是将您的规则命名与您的事实不同,如下所示:

kindoflikes(tom,jerry).
kindoflikes(mary,john).
kindoflikes(mary,mary).
kindoflikes(tom,mouse).
kindoflikes(jerry,jerry).
kindoflikes(jerry,cheese).
kindoflikes(mary,fruit).
kindoflikes(john,book).
kindoflikes(mary,book).
kindoflikes(tom,john).

likes(Y,X):- kindoflikes(X,Y), X\=Y.
likex(Y,X):- kindoflikes(Y,X), X\=Y.

请注意,在两个规则定义中,kindoflikes中的X和Y是相反的。因此你会得到:
?- likes(john,X).
X = mary ;
X = tom ;
X = book.

但您并不局限于找到约翰喜欢的东西,您可以执行:
?- likes(jerry,X).
X = tom ;
X = cheese.

@GregHNZ:Prolog在事实之前不执行规则。 - m09

2
您的第一个问题是为什么程序崩溃。我不确定您使用的是什么类型的Prolog系统,但许多系统会产生一个干净的“资源错误”,可以从Prolog内部处理。
您实际遇到的问题是,对于查询likes(john, X),您的程序没有终止。它给出了预期的答案,然后才进入循环。
?- likes(john,X).
   X = book
;  X = mary
;  X = tom
;  resource_error(local_stack). % ERROR: Out of local stack
您非常幸运能够迅速检测到这个问题。想象一下有更多的答案,那么您就没有耐心去查看所有答案了,这不会那么明显。但是,有一种快捷方式。改为询问:
?- likes(john, X), false.
这个“false”目标永远不会成立,因此它很容易阻止任何答案。最好的情况是,以“false”结尾的查询会终止。但目前情况并非如此。导致这种非终止的原因最好从以下(查找其他答案获取更多细节)中考虑。
英译中:
?- likes(john,X), false.
   循环。

likes(tom,jerry) :- false.
likes(mary,john) :- false.
likes(mary,mary) :- false.
likes(tom,mouse) :- false.
likes(jerry,jerry) :- false.
likes(jerry,cheese) :- false.
likes(mary,fruit) :- false.
likes(john,book) :- false.
likes(mary,book) :- false.
likes(tom,john) :- false.
likes(john,X) :-
   likes(X,john), false,
   X\=john,
   dif(X, john).

因此,你的程序的这个小部分是导致堆栈溢出的原因。要解决问题,我们必须在这个小部分做一些修改。这里有一个方法:添加一个目标dif(X, john),使规则现在变成:

likes(john,X) :- dif(X, john), likes(X,john).
“likes(john,X)”表示“约翰喜欢X”,“dif(X, john)”表示“X不等于约翰”,“likes(X,john)”表示“X喜欢约翰”。所以整个句子的意思是“如果X不等于约翰并且X喜欢约翰,那么约翰也喜欢X”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接