本书Structure and Interpretation of Computer Programs的练习1.3要求如下:
定义一个过程,该过程将三个数字作为参数,并返回两个较大数字的平方和。
我正在学习Prolog。这是我试图实现的功能:
square(X, Y) :- Y is X * X.
squareTwoLargest(X, Y, Z, R) :-
R is square(L1) + square(L2), L1 = max(X, Y), L2 = max(min(X, Y), Z).
但是,当我运行它时,会出现以下错误:ERROR: is/2: Arguments are not sufficiently instantiated
。我想我不仅没有得到Prolog的语法,而且我还没有得到逻辑编程范式。那么,我怎样才能以良好的逻辑编程风格实现这个功能呢?
答案 0 :(得分:2)
要获得三个中最大的两个数字(V1
,V2
和V3
),您可以按以下步骤操作:对列表[V1,V2,V3]
进行排序并选择最后一个两个列表项[_,X,Y]
,平方并将它们相加。
:- use_module(library(lists)).
:- use_module(library(clpfd)).
squareTwoLargest(V1,V2,V3, R) :-
Zs = [_,X,Y],
chain(Zs, #=<),
permutation([V1,V2,V3],Zs),
R #= X*X + Y*Y.
示例查询:
?- squareTwoLargest(20,30,10, R).
R = 1300
以上代码基于&#34;排列排序&#34;,这使得它在多种方式下效率低下。
如果squareTwoLargest(X,Y,Z, R)
,X
和Y
中的两个或多个相等,则目标Z
会多次成功并提供多余的答案。这由以下两个查询显示:
?- squareTwoLargest(0,10,10, R).
R = 200 ;
R = 200 ;
false.
?- squareTwoLargest(10,10,10, R).
R = 200 ;
R = 200 ;
R = 200 ;
R = 200 ;
R = 200 ;
R = 200 ;
false.
我们可以使用大小为3的排序网络来消除冗余答案。有关详细信息,请查看问题的this answer ordering lists with constraint logic programming
list_sorted__SN3([A0,A1,A2], [D0,D1,C2]) :-
B1 #= min(A1,A2), B2 #= max(A1,A2),
C0 #= min(A0,B2), C2 #= max(A0,B2),
D0 #= min(C0,B1), D1 #= max(C0,B1).
squareTwoLargest__SN(V1,V2,V3, R) :-
list_sorted__SN3([V1,V2,V3],[_,X,Y]),
R #= X*X + Y*Y.
考虑以下问题:
?- squareTwoLargest__SN(20,30,10, R).
R = 1300. % works like it did before
?- squareTwoLargest__SN(20,20,10, R).
R = 800. % succeeds deterministically
?- squareTwoLargest__SN(20,20,20, R).
R = 800. % succeeds deterministically
请注意,上面显示的角落案例的所有冗余答案都已消除。
答案 1 :(得分:1)
不幸的是,你正在使用的max
函数是内置的算术函数,并且不像谓词那样,这可能会让你误以为你会以相同的方式编写谓词。
在Prolog中,你将要写的是谓词。谓词不会返回任何值,它只是保持或不成立(您可以将其视为返回true
或false
)。你的谓语square
就是一个很好的例子,它square(X,Y)
的真正含义是“Y”是X&#39;的平方。如果您询问Prolog控制台square(4, 16).
,它会告诉您true
。如果您问square(4, 44)
,它会告诉您false
。那你如何找出一些数字的平方根?你问Prolog一个带有免费(未知)变量square(4,R).
的问题,然后Prolog会告诉你R=16
。这是逻辑编程的重要部分,你不解释Prolog,如何计算平方,你只告诉Prolog什么方块在逻辑上然后你问Prolog问题它会自己找到答案。
如果你尝试而不是
,那该怎么办?R is square(L1) + square(L2)
类似
square(L2, L2SQUARED), square(L1, L1SQUARED), ...
将在L1SQUARED
中给出L1的平方但是,L1不能是自由变量,Prolog必须能够根据其他谓词(...)推导出某些值,以便它可以回答square(L1, L1SQUARED)
。想象一下问题square(SOMETHING1, SOMETHING2)
,其中两个论点都是未知的,答案是什么?有无数正确的答案,例如[2,4]或[3,9]等。
注意:是的,它可以与算术联机,但如果您想学习逻辑编程,请尝试更多的逻辑编程&#39;喜欢的方法。在Prolog的某些风格中,你没有得到算术,它们仍然有用......
答案 2 :(得分:1)
我的赌注,使用&#39; if-then-else&#39;构造
squareTwoLargest(X, Y, Z, R) :-
( X > Y -> A = X, B = Y ; A = Y, B = X ),
R is A + max(B, Z).
需要两个临时变量。