Prolog 程序获取一个(整数)数作为两个整数平方和,为什么它不起作用?

Prolog program to get an (integer) number as the sum of two integer squares, why does it not work?

我正在开始学习 Prolog,我想要一个给定整数 P 的程序给出整数 AB 使得 P = A² + B²。如果没有 AB 的值满足此等式,则应返回 false

例如:如果P = 5,它应该给出A = 1B = 2(或A = 2B = 1),因为1² + 2² = 5

我认为这应该可行:

giveSum(P, A, B) :- integer(A), integer(B), integer(P), P is A*A + B*B.

与查询:

giveSum(5, A, B).

然而,事实并非如此。我应该怎么办?我对 Prolog 很陌生,所以我仍然犯了很多错误。

提前致谢!

integer/1 是一个非单调谓词。它是 而不是 允许您期望在这种情况下应用的推理的关系。举个例子:

?- integer(I).
false.

不存在整数,是吗? 让我惊讶,至少可以这么说!

使用您的 Prolog 系统的 CLP(FD) 约束 来推理整数,而不是此类非关系结构。

例如:

?- 5 #= A*A + B*B.
A in -2..-1\/1..2,
A^2#=_G1025,
_G1025 in 1..4,
_G1025+_G1052#=5,
_G1052 in 1..4,
B^2#=_G406,
B in -2..-1\/1..2

具体解决方案:

?- 5 #= A*A + B*B, label([A,B]).
A = -2,
B = -1 ;
A = -2,
B = 1 ;
A = -1,
B = -2 ;
etc.

CLP(FD) 约束是完全纯粹的关系,可以按您期望的方式使用。有关详细信息,请参阅

我注意到的其他事情:

  • use_underscores_for_readability_as_is_the_convention_in_prolog 而不是 ofMixingTheCasesToMakePredicatesHardToRead.
  • 使用声明性名称,避免 命令式。比如为什么叫give_sum?如果总和 已经给出 ,这个谓词也很有意义。那么,例如 sum_of_squares/3 呢?

为了效率的缘故,Prolog 的实现者选择了——很多很多年前——一些妥协。现在,您的 Prolog 有可能实现高级整数运算,就像 CLP(FD) 那样。如果是这种情况,垫子的答案是完美的。但是一些 Prolog(可能是天真的 ISO Prolog 兼容处理器)可能会抱怨缺少 label/1 和 (#=)/2。因此,传统的 Prolog 解决方案:该技术称为 generate and test:

giveSum(P, A, B) :-
  ( integer(P) -> between(1,P,A), between(1,P,B) ; integer(A),integer(B) ),
  P is A*A + B*B.

between/3 它不是内置的 ISO,但它比 (#=)/2 和 label/1 更容易编写:)

无论如何,请听从 mat 的建议并避免 'imperative' 命名。通常对关系的描述更好,因为 Prolog 就是这样:一种关系语言。