2

《计算机程序的结构和解释》一书的练习 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 的语法,而且还没有得到逻辑编程范式。那么,我怎样才能以良好的逻辑编程风格实现这个功能呢?

4

3 回答 3

2

要得到三个( 、 和 )中最大的两个数,V1V2可以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 

更好的实施

上面的代码是基于“排列排序”的,这使得它在不止一个方面效率低下。

如果、 和中的两个或多个相等,则目标squareTwoLargest(X,Y,Z, R)多次成功并给出冗余答案。这由以下两个查询显示:XYZ

?- 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 的排序网络来消除冗余答案。有关详细信息,请查看带有约束逻辑编程的问题 排序列表的答案

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 

请注意,上面显示的极端情况的所有冗余答案都已被消除。

于 2015-04-14T09:13:55.597 回答
1

不幸的是,max您正在使用的函数是内置的算术函数,并且不表现为谓词,这可能会让您误以为您将以相同的方式编写谓词。

在 Prolog 中,您将编写的是谓词。Predicate 不返回任何值,它只是持有或不持有(你可以把它想象成它返回了trueor false)。您的谓词square是一个很好的例子,它square(X,Y)的真正含义是'Y 是 X 的平方'。如果你问 Prolog 控制台square(4, 16).,它会告诉你true。如果你问square(4, 44),它会告诉你false。那么如何找出某个数字的平方根呢?你问 Prolog 一个带有自由(未知)变量的问题square(4,R).,然后 Prolog 会告诉你R=16。这是逻辑编程的重要部分,你不解释Prolog,如何计算平方,你只告诉Prolog什么是逻辑平方,然后你问Prolog问题,它会自己找到答案。

Soo 如果你尝试而不是

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] 等。

注意:是的,它可以在线使用算术,但是如果您想学习逻辑编程,请尝试更多类似“逻辑编程”的方法。在 Prolog 的某些风格中,你没有得到算术,它们仍然很有用......

于 2015-04-13T20:11:12.527 回答
1

我敢打赌,使用“if-then-else”结构。

squareTwoLargest(X, Y, Z, R) :- 
    ( X > Y -> A = X, B = Y ; A = Y, B = X ),
    R is A + max(B, Z).

需要两个临时变量。

于 2015-04-13T20:25:33.247 回答