2

一个查询sum(X,Y)将回答 X 的所有正除数的总和(不包括 X 本身)说,sum(12,Y)将回答Y=16因为 1、2、3、4、6 是 12 的除数。

我打算实现以下 prolog 程序,但它失败了,说一些变量没有实例化。

sum(X,Y) :- f(X,Y,1).
f(X,Y,F) :- X>Y,X>F, 0 is X mod F, F1 is F+1, f(X,Y1,F1), Y is F+Y1.
f(X,Y,F) :- X>Y,X>F, not(0 is X mod F), F1 is F+1, f(X,Y,F1).

上述程序有什么问题?

谢谢你的帮助!

4

2 回答 2

2

我不会向您展示如何编写 sum_of_divisors 函数,因为它不会很有启发性。相反,我可以尝试向您展示如何理解您的sum(12,Y)查询出了什么问题。

让我们看看错误:

?- sum(12, Y).
ERROR: >/2: Arguments are not sufficiently instantiated
   Exception: (8) f(12, _G215, 1) ? a
% Execution Aborted

查询后

?- sum(12, Y).

Prolog 引擎读取sum(X,Y) :- f(X,Y,1).并评估第二个谓词:

f(X,Y,F) 

其中X = 12,F = 1Y不受约束。所以它尝试这个:

:- X>Y

这是

12 > _G350

其中_G350Y,一个未实例化的变量。

问题是算术谓词 like (>)/2(and like (+)/2and (*)/2, etc..) 要求您要比较的两个变量都是实例化的。你不能这样查询:

?- 12 > X

并期望 Prolog 引擎找到所有小于 12 的绑定。因此,您需要重新考虑解决问题的方法,并记住您只能使用 NUMBERS 进行算术运算,而不能使用数字和变量XX

于 2012-12-03T21:31:41.747 回答
2

对于完整的声明性算术,您可以按照已经建议的方式使用 CLP(FD)。例如,在 SWI-Prolog 中,当我简单地将 (is)/2 替换为 (#=)/2 等以概括原始算术运算以便它们也可以与两侧的变量一起使用时,我得到:

:- use_module(library(clpfd)).

sum(X,Y) :- f(X,Y,1).

f(X,Y,F) :- X#>Y,X#>F, 0 #= X mod F, F1 #= F+1, f(X,Y1,F1), Y #= F+Y1.
f(X,Y,F) :- X#>Y,X#>F, 0 #\= X mod F, F1 #= F+1, f(X,Y,F1).

现在您的示例查询产生:

?- sum(12, Y).
false.

所以很明显程序太具体了,检查一下你是否忘记描述一个重要的案例。

于 2012-12-03T22:12:36.563 回答