使用序言查找三个数字之间的最大数

Finding the maximum number between three numbers using prolog

我从昨天开始学习序言,我被告知要找到三个数字之间的最大数字。我正在使用 SWI Prolog,这是我到目前为止编写的程序。

% If-Elif-Else statement

gte(X,Y,Z) :- X > Y,write('X is greater').
gte(X,Y,Z) :- X =:= Y,write('X and Y are same').
gte(X,Y,Z) :- X < Y < Z,write('Y is greater').
gte(X,Y,Z) :- X < Z,write('Z is greater').
gte(X,Y,Z) :- X > Z,write('X is greater').
gte(X,Y,Z) :- Y > Z,write('Y is greater').
gte(X,Y,Z) :- Y < Z,write('Z is greater').
gte(X,Y,Z) :- X=:=Z,write('X and Z are same').
gte(X,Y,Z) :- Y=:=Z,write('Y and Z are same').

输出应该是 ->

gte(12,24,36)
 24 is greater.
True

而是给我看这个

Warning: c:/users/i3/documents/prolog/test.pl:3:
Warning:    Singleton variables: [Z]
Warning: c:/users/i3/documents/prolog/test.pl:4:
Warning:    Singleton variables: [Z]
Warning: c:/users/i3/documents/prolog/test.pl:5:
Warning:    Singleton variables: [Z]
Warning: c:/users/i3/documents/prolog/test.pl:6:
Warning:    Singleton variables: [Y]
Warning: c:/users/i3/documents/prolog/test.pl:7:
Warning:    Singleton variables: [Y]
Warning: c:/users/i3/documents/prolog/test.pl:8:
Warning:    Singleton variables: [X]
Warning: c:/users/i3/documents/prolog/test.pl:9:
Warning:    Singleton variables: [X]
Warning: c:/users/i3/documents/prolog/test.pl:10:
Warning:    Singleton variables: [Y]
Warning: c:/users/i3/documents/prolog/test.pl:11:
Warning:    Singleton variables: [X]
true.

我不明白这个程序的错误在哪里。

学习 Prolog 的很大一部分是学习 递归地思考 。所以....

你应该首先解决最简单的问题:两个数中较大的一个是多少?这很简单,对吧?

max( X, X , X ) .
max( X, Y , X ) :- X > Y .
max( X, Y , Y ) :- X < Y .

现在我们可以做到这一点,扩展解决方案 space 以考虑 3 个值也很容易:只需确定第一个两个值的最大值,然后是那个最大值和第三个值:

max( X , Y , Z , R ) :- max(X,Y,T), max(T,Z,R).

进一步扩展解决方案以考虑任意数量的值也很容易:只需重复上述过程,直到您将列表筛选为单个值。

max( [Z]      , Z ) .  % the max of a 1-item list is that item.
max( [X,Y|Zs] , M ) :- % the max of a list of 2+ items can be found by...
  max(X,Y,Z) ,         % - find the max of the first two items, and
  max([Z|Zs],M)        % - recursing down, replacing those two items with that max value
  .                    % Easy!

[编辑注释] 确定一列数字最大值的基本算法是:

  • 虽然列表的长度大于 1,
    • 确定列表的前两个元素中较大的一个
    • [递归地用两个值中的较大者替换​​列表的第一个两个元素

因此在递归的每次迭代中,源列表的长度减 1,列表的头部始终是当前 high-water 标记,即当前最大值。一旦列表的长度减为一,我们就解决了手头的问题。

可以将 max/3max/2 合并为一个谓词:

max( [X]      , X ) .
max( [X,Y|Zs] , R ) :- X =:= Y , max( [X|Zs] , R ) .
max( [X,Y|Zs] , R ) :- X  >  Y , max( [X|Zs] , R ) .
max( [X,Y|Zs] , R ) :- X  <  Y , max( [Y|Zs] , R ) .

但我认为找到 2 个值中的最大值是一个非常常见的特例,值得将其分解成自己的谓词:max(X,Y,Max).

也可以使用带有额外参数的辅助谓词,该参数显式携带额外状态,即当前高值,因此:

max( [X|Xs] , R ) :- max(Xs,X,R) .

max( []     , R , R ) .
max( [X|Xs] , Y , R ) :- X =:= Y , max(Xs,Y,R) .
max( [X|Xs] , Y , R ) :- X  <  Y , max(Xs,Y,R) .
max( [X|Xs] , Y , R ) :- X  >  Y , max(Xs,X,R) .

所以在上面,我们简单地弹出源列表的头部,并调用带有该值种子的累加器的助手。源列表用完后,累加器将包含所需的结果。

TIMTOWTDI[1] 正如他们所说。

[1] 方法不止一种