3

我在序言中有以下奇数和偶数生成器

even(0).
even(X) :- odd(Y), X is Y+1, X>0.

odd(1).
odd(X) :- even(Y), X is Y+1, X>1.

我想了解为什么我不能将这些函数用作测试人员,即?even(3).这会导致无限循环。

这不是我打电话时发生的事情?even(3).吗?

X被实例化为3. 尝试找到任何奇怪Y的(从 开始0)。发现Y=1。现在是我不明白的部分。我不知道当它必须处理该子句时会发生什么X is Y+1。考虑X已经给出了,这里发生了什么?

4

4 回答 4

4

您在这里尝试了解程序的精确终止属性,当您来自过程语言时,这有点令人惊讶。在 Prolog 中,有几个交错的控制流,这使得实际执行通常难以遵循。

要理解它,您可以逐步跟踪程序以了解实际发生的情况,但该方法很快就会变得复杂。而且您的程序尽可能简单。相反,我将向您展示另一种方法,使用failure-slices

您很幸运地使用了even(3)立即显示存在问题的查询。您可以使用另一个查询,例如even(2).它不会立即向您显示问题。事实上,Prolog 很好地完成了这个查询。一切似乎都很好,除非您要求查看更多答案。

那么我们如何才能确保我们尽快面对问题呢?一种方法是改为提出查询even(2), false。在这种情况下,我们预计查询会失败,因为false永远不会成功。但是,查询可能会产生无限循环(或错误),而不是失败。通过false在末尾添加我们说:跳过所有答案,并简单地显示查询是否终止。

现在(纯的、单调的)Prolog 的好处是我们可以对你的程序做同样的事情。因此,我们可能会将目标添加false到您的计划中。如果生成的程序(称为故障切片)现在循环,那么原始程序实际上也将循环。

这是仍然循环的最小故障片:

偶数(0):-。
偶数(X):-奇数(Y),X是Y+1,X>0奇数(1):-。
奇数(X):-偶数(Y),X是Y+1,X>1

正是这个微小的剩余部分负责所有循环。现在,您不仅可以证明为什么even(2)会循环,还可以看到更一般的情况:这个失败切片将独立于 for 的参数循环even/1。所以它将循环任何查询

有关更多信息,请参阅

于 2013-09-11T22:36:58.813 回答
3

X is Y + 1目标变为3 is 1 + 1并且它失败了,导致回溯之前的调用,odd(Y). 这轮流使用odd/1谓词的第二个子句来尝试找到替代解决方案。第二个子句主体调用even(Y)实例化Y0然后尝试X is 0+1, X>1,失败导致回溯到对even/1谓词的先前调用。odd/1从这里开始就像是和even/1谓词之间的一场永无止境的乒乓球游戏。您可以使用您的 Prolog 编译器trace功能来一步一步地跟踪正在发生的事情。

还要注意,在 Prolog 中,变量是子句的局部变量。也许这就是让你感到困惑的地方?

于 2013-09-11T21:10:55.557 回答
1

当您调用even(3)(所以,作为测试)时,3 与 0 不匹配,因此它属于复合子句。

该子句所做的第一件事是调用odd未绑定的变量 Y,因此作为生成器。它最终成功的唯一方法是如果odd(Y)可以返回一个奇数 Y 使得3 is Y+1. 生成器将返回 1、3、5 等,所以这永远不会发生。但是 Prolog 无法知道这一点,所以它所能做的就是全部尝试。它们碰巧有无穷大[*],因此是无限循环。

[*] 取决于您的 Prolog 实现的整数设置,但无论它是否真正完成都需要很长时间。

于 2013-09-11T21:16:40.827 回答
0

要使 Prolog 代码双向,您必须为不同的模式添加子句,并使用元变量测试器 var/1 在两个变体之间做出决定:

生成器:

even(0).
even(X) :- odd(Y), X is Y+1, X>0.

odd(1).
odd(X) :- even(Y), X is Y+1, X>1.

测试者:

even(0).
even(X) :- X>0, Y is X-1, odd(Y).

odd(1).
odd(X) :- X>1, Y is X-1, even(Y).

双向代码:

even(0).
even(X) :- var(X), !, odd(Y), X is Y+1, X>0.
even(X) :- X>0, Y is X-1, odd(Y).

odd(1).
odd(X) :- var(X), !, even(Y), X is Y+1, X>1.
odd(X) :- X>1, Y is X-1, even(Y).

Prolog 系统、库和用户代码通过这种技术实现了许多谓词。一个原因可能是使用这种双向谓词可以简化其他双向谓词的定义。

但事情并没有那么简单,因为当谓词是组合目标时,可能仍需要重新排序。所以也许我们只是为了保存命名空间。顺便说一句,这里是双向 between/3 实现。

于 2016-10-06T14:06:02.143 回答