微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

更好地理解序言

如何解决更好地理解序言

我正在尝试了解 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,B).

然后当我说 jealous(1,4) 时它起作用了。

解决方法

然后当我说 jealous(1,4)

时它起作用了

不,它没有。或者,嗯,有点。只需输入 SPACE 即可看到它再次循环。那么立即循环的 jealous(4,1) 呢?

要理解这一点,只需查看程序的一小部分即可:

jealous(A,B) :- false, hates(A,B).
jealous(A,B) :- jealous(A,C),false, jealous(C,B).

注意变量 B 从未在可见部分使用。所以它不会对终止产生任何影响。并注意刚刚交给第一个目标的 A。所以这两个参数在这个程序中都没有影响。因此该程序永不终止。它可能会在这里和那里找到解决方案,但当被要求找到所有解决方案时,它永远不会终止。

这个小片段称为 ,如果它不终止,整个程序也会终止!也就是说,根本不需要阅读您对 hates/2 的定义1

如果你想掌握 Prolog 的执行,你需要掌握失败切片的概念。因为,有经验的程序员或多或少是凭直觉做到这一点的。因此,他们不会阅读整个程序,他们只是扫描相关部分。 Prolog 的好处在于,这样的切片与整个程序之间存在真正的因果关系。

要解决此问题,您需要更改故障切片突出显示的部分中的某些内容。这是一种可能的变化:

jealous(A,B) :- hates(A,B).
jealous(A,jealous(C,B).

但是一旦您在 hates/2 中有循环,这将不再有效。然后,考虑closure/3

jealous(A,B) :-
   closure(hates,A,B).

另一种方法是使用表格。但请注意,制表解决了这一问题,但在有约束的情况下将不再有效(您迟早会遇到这种情况)。


1) 前提是你有一个纯单调的程序。

,

如果您使用的是 SWI-Prolog 或 XSB Prolog,您可以尝试添加:

:- table jealous/2.

它应该可以工作(我还没有尝试过 - 但这里有一个类似的例子:https://www.swi-prolog.org/pldoc/man?section=tabling-non-termination)。

您的问题是 Prolog 默认执行策略,即从左到右深度优先。您可以通过将最后一个子句更改为:

来避免这种情况
jealous(A,B).

(Prolog教科书中有很多类似的例子)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。