我需要 SWI-prolog 中的简单函数来乘以加法。像 m(X,Y,Z) 这样的东西,例如 X=5, Z=3 <==> 5*3。Y 是结果:Y=5、Y=10、Y=15 [停止]。我在想这样的事情:
m(X,Y,Z):- Z>0, /*when Z reaches 0 you stop */ I=X+X, W=Z-1, m(I,Y,W).
Run Code Online (Sandbox Code Playgroud)
但它总是返回“false”,不知道为什么。
让我们首先考虑谓词应该描述什么:它是三个数字之间的关系,其中第三个数字是前两个数字的乘积。由于您想通过将第二个参数减少到零来描述乘法,同时将第一个参数相加多次,我们正在讨论自然数。因此,一个具有良好描述性的名称是 nat_nat_prod/3。接下来考虑可能的情况:
第二个参数可以为零。那么乘积也必须为零,因为 X*0=0。这是基本情况。
否则第二个参数大于零。然后您想要将其减一并计算第一个参数和这个新数字的乘积。由于谓词可以使用自身来描述它,因此这是一个递归目标。随后,您将第一个参数添加到递归描述的中间产品中。
这可以在 Prolog 中这样写:
nat_nat_prod(_X,0,0). % case 1)
nat_nat_prod(X,Y1,P1) :- % case 2)
Y1 > 0,
Y0 is Y1-1,
nat_nat_prod(X,Y0,P0),
P1 is P0+X.
Run Code Online (Sandbox Code Playgroud)
现在让我们尝试一些查询:
?- nat_nat_prod(5,3,P).
P = 15 ;
false.
?- nat_nat_prod(5,4,P).
P = 20 ;
false.
?- nat_nat_prod(5,0,P).
P = 0 ;
false.
?- nat_nat_prod(1,0,P).
P = 0 ;
false.
?- nat_nat_prod(1,1,P).
P = 1 ;
false.
Run Code Online (Sandbox Code Playgroud)
但是,在使用谓词时,您会注意到前两个参数必须实例化,否则您会收到错误:
?- nat_nat_prod(1,Y,3).
ERROR: >/2: Arguments are not sufficiently instantiated
?- nat_nat_prod(X,1,3).
ERROR: is/2: Arguments are not sufficiently instantiated
Run Code Online (Sandbox Code Playgroud)
发生这种情况是由于使用了 >/2 和 is/2。您可以通过使用 CLP(FD) 来解决这个问题,但我认为这不是重点。与使用标准算术函数 */2 相比,这种定义乘法的方式显然效率很低,例如:
?- time(nat_nat_prod(2,1000000,P)).
% 3,000,000 inferences, 33.695 CPU in 33.708 seconds (100% CPU, 89035 Lips)
P = 2000000 ;
% 3 inferences, 0.031 CPU in 0.031 seconds (100% CPU, 97 Lips)
false.
?- time(P is 2*1000000).
% 1 inferences, 0.000 CPU in 0.000 seconds (86% CPU, 82325 Lips)
P = 2000000.
Run Code Online (Sandbox Code Playgroud)
正如 @false 在评论中已经暗示的那样,更常见的是首先向人们介绍后继算术,然后以这种方式定义 s(X) 表示法中两个数字的加法/乘法。由于您无法将标准算术函数与 s(X) 数字一起使用,因此您也不会遇到相关的实例化错误。