Prolog:如何实现三个中两个最大数字的平方和?

时间:2015-04-13 19:46:50

标签: prolog sicp logic-programming

本书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的语法,而且我还没有得到逻辑编程范式。那么,我怎样才能以良好的逻辑编程风格实现这个功能呢?

3 个答案:

答案 0 :(得分:2)

要获得三个中最大的两个数字(V1V2V3),您可以按以下步骤操作:对列表[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)XY中的两个或多个相等,则目标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中,你将要写的是谓词。谓词不会返回任何值,它只是保持或不成立(您可以将其视为返回truefalse)。你的谓语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).

需要两个临时变量。