Prolog 程序获取一个(整数)数作为两个整数平方和,为什么它不起作用?
Prolog program to get an (integer) number as the sum of two integer squares, why does it not work?
我正在开始学习 Prolog,我想要一个给定整数 P
的程序给出整数 A
和 B
使得 P = A² + B²
。如果没有 A
和 B
的值满足此等式,则应返回 false
例如:如果P = 5
,它应该给出A = 1
和B = 2
(或A = 2
和B = 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) 约束是完全纯粹的关系,可以按您期望的方式使用。有关详细信息,请参阅 clpfd。
我注意到的其他事情:
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 就是这样:一种关系语言。
我正在开始学习 Prolog,我想要一个给定整数 P
的程序给出整数 A
和 B
使得 P = A² + B²
。如果没有 A
和 B
的值满足此等式,则应返回 false
例如:如果P = 5
,它应该给出A = 1
和B = 2
(或A = 2
和B = 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) 约束是完全纯粹的关系,可以按您期望的方式使用。有关详细信息,请参阅 clpfd。
我注意到的其他事情:
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 就是这样:一种关系语言。