所有正除数的总和

时间:2012-12-03 19:06:58

标签: prolog

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

上述程序的问题是什么?

谢谢你的帮助!

2 个答案:

答案 0 :(得分: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 = 12F = 1Y未绑定。所以它尝试这个:

:- X>Y

12 > _G350

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

问题是算术谓词如(>)/2(以及(+)/2(*)/2等)要求将要比较的变量实例化。你不能这样查询:

?- 12 > X

并期望Prolog引擎找到X的所有绑定,使X小于12.所以你需要重新思考问题的方法,并记住你能做到算术只有NUMBERS,而不是数字和变量。

答案 1 :(得分:2)

对于完整的声明性算术,您可以使用已建议的CLP(FD)。例如,在SWI-Prolog中,当我简单地用(#=)/ 2等替换(is)/ 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.

很明显,该程序过于具体,请检查您是否忘记描述重要案例。