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

时间:2012-04-28 03:06:10

标签: prolog prolog-dif failure-slice

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

有什么建议吗?

2 个答案:

答案 0 :(得分: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.

答案 1 :(得分:2)

您的第一个问题是您的程序崩溃的原因。我不确定你使用的是什么样的Prolog系统,但是很多系统都会产生一个干净的“资源错误”,可以在Prolog中处理。

您的实际问题是您的程序不会终止查询likes(john, X)。它为您提供了预期的答案,然后才循环。

?- likes(john,X).
X = book ;
X = mary ;
X = tom ;
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),使规则现在为:

likes(john,X) :-
   dif(X, john),
   likes(X,john).

dif/2可用于许多Prolog系统,例如:SICStus,SWI,YAP,B,IF。