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).

程序崩溃。likes(john,john)原因是即使规则规定了prolog 也会卡住X\=john

有什么建议吗?

4

2 回答 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.
于 2012-04-28T04:11:52.407 回答
2

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

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

?- 喜欢(约翰,X)。
X = 书;
X = 玛丽;
X = 汤姆;
错误:超出本地堆栈

您很幸运能够如此迅速地发现该问题。想像更多的答案,你有耐心看完所有答案就不是那么明显了。但有一条捷径。而是问:

?- 喜欢(约翰,X),

这个false目标永远不会是真的。所以它很容易阻止任何答案。充其量,最后的查询false会终止。目前情况并非如此。在考虑以下时,最好看到这种不终止的原因(查找其他答案以获取更多详细信息):

?- 喜欢(约翰,X),喜欢(汤姆,杰瑞):-喜欢(玛丽,约翰):-喜欢(玛丽,玛丽):-喜欢(汤姆,鼠标):-喜欢(杰瑞,杰瑞):-的。
喜欢(杰瑞,奶酪):-错误喜欢(玛丽,水果):-喜欢(约翰,书):-喜欢(玛丽,书):-喜欢(汤姆,约翰):-。
喜欢(约翰,X):-
   喜欢(X,约翰),X\=约翰

因此,正是程序的这一小部分负责堆栈溢出。为了解决这个问题,我们必须在那个很小的部分做点什么。这是一个:添加一个目标dif(X, john),使得规则现在变为:

喜欢(约翰,X):-
   差异(X,约翰),
   喜欢(X,约翰)。

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

于 2012-11-14T21:01:43.607 回答