【问题标题】:Find max integer in a list in prolog在prolog的列表中查找最大整数
【发布时间】:2015-07-23 16:57:42
【问题描述】:

我正在尝试在列表中查找最大数量。我知道网上有多种解决方案,但我觉得最好的学习方式是自己实施。

我写了以下代码:

max([X],X).
max([H|T],Res):-
    (  H >= Res
    -> max(T,Res1), Res1 = H
    ;  max(T,Res)
    ).

谁能指出我的错误?我想不通。

【问题讨论】:

  • 一个问题是Res 没有在对max 的查询中实例化。
  • 尝试“思考不同(Prolog)”!列表的最大值是多少?它是此列表的成员 E,并且此列表中没有其他元素大于 E。
  • 您需要向max 引入另一个变量,并且可以使用辅助谓词(可以是max/3max/2)来做到这一点。这是一个开端:max([H|T], Max) :- max(T, H, Max). 这表示,Max 是列表 [H|T] 的最大值,如果 Max 是列表 T 中的最大值和值 H 中的最大值(最后一个最大值看到的值)。现在,您需要定义max(List, MaxSeenSoFar, Max),现在您已经实例化了MaxSeenSoFar,因此您可以使用将[H|T] 中的HMaxSeenSoFar 进行比较的逻辑。

标签: prolog max


【解决方案1】:

考虑my answer 中提供的代码到相关问题“Finding the max in a list - Prolog”。

上述答案中的代码基于foldl/4

在这里,我将展示如何使用元谓词 combine/3reduce/3 来实现。一、combine/3

:- meta_predicate combine(3,?,?).
combine( _ ,[]    ,[]).
combine(P_3,[X|Xs],Ys) :-
   list_prev_combined_(Xs,X,Ys,P_3).

:- meta_predicate list_combined_(?,?,3).
list_combined_([]    ,[], _ ).
list_combined_([X|Xs],Ys,P_3) :-
   list_prev_combined_(Xs,X,Ys,P_3).

:- meta_predicate list_prev_combined_(?,?,?,3).    
list_prev_combined_([]     ,X ,[X]   , _ ).
list_prev_combined_([X1|Xs],X0,[Y|Ys],P_3) :-
   call(P_3,X0,X1,Y),
   list_combined_(Xs,Ys,P_3).

combine/3 的基础上,我们可以定义reduce/3 如下:

:- meta_predicate reduce(3,?,?).
reduce(P_3,[X|Xs],V) :- 
   list_aka_prev_reduced_(Xs,Xs,X,V,P_3).

:- meta_predicate list_aka_prev_reduced_(?,?,?,?,3).
list_aka_prev_reduced_([]   ,_ ,V ,V, _ ).
list_aka_prev_reduced_([_|_],Xs,X0,V,P_3) :-
   list_prev_combined_(Xs,X0,Ys,P_3),
   reduce(P_3,Ys,V).

关于它们各自的证明树的形状,foldl/4 类似于列表,而combine/3reduce/3 类似于平衡二叉树。

考虑以下查询:

:- use_module(library(lambda)).

?- foldl(\X^Y^f(X,Y)^true, [1,2,3,4,5,6,7], 0,S).
S = f(7,f(6,f(5,f(4,f(3,f(2,f(1,0))))))).

?- combine(\X^Y^f(X,Y)^true, [1,2,3,4,5,6,7], S).
S = [f(1,2),f(3,4),f(5,6),7].

?- reduce(\X^Y^f(X,Y)^true, [1,2,3,4,5,6,7], S).
S = f(f(f(1,2),f(3,4)),f(f(5,6),7)).

reduce/3 基于combine/3 并应用它,直到所有项目合并为一个:

?- 结合(\X^Y^f(X,Y)^true, [1,2,3,4,5,6,7], S)。 S = [f(1,2),f(3,4),f(5,6),7]。 ?- 结合(\X^Y^f(X,Y)^true, [f(1,2),f(3,4),f(5,6),7], S)。 S = [f(f(1,2),f(3,4)),f(f(5,6),7)]。 ?- 结合(\X^Y^f(X,Y)^true, [f(f(1,2),f(3,4)),f(f(5,6),7)], S )。 S = [f(f(f(1,2),f(3,4)),f(f(5,6),7))]。 ?- 减少(\X^Y^f(X,Y)^true, [1,2,3,4,5,6,7], S)。 S = f(f(f(1,2),f(3,4)),f(f(5,6),7))

让我们用它来获取列表[1,5,2,4,3,8,7,2]中的最大整数Max

:- 使用模块(库(clpfd))。 ?- 减少(\X^Y^XY^(XY #= max(X,Y)), [1,5,2,4,3,8,7,2], Max)。 最大值 = 8。 ℅ 如果不能使用 clpfd,只需使用 is/2 代替 (#=)/2: ?- 减少(\X^Y^XY^(XY is max(X,Y)), [1,5,2,4,3,8,7,2], Max)。 最大值 = 8。

【讨论】:

    【解决方案2】:

    您没有确保 Res 被实例化。你不需要一个辅助谓词来做到这一点。您可以在检查Res 是否大于H 之前进行递归调用,其中ResT 的最大整数。

    您可以使用->,但不是必须的。但如果你不这样做,就会涉及更多的回溯。

    如果您在检查后尝试通过递归更多地停留在您的路线上,您将需要一个辅助谓词,正如 lurker 所建议的那样。

    编辑:既然现在已经接受了答案,下面是实施的三个建议:

    max1([H|T], Y):-  % with the -> operator, call first
        max1(T,X),
        (H > X ->
         H = Y;
         Y = X).
    max1([X],X).
    
    
    max2([H|T], Y):-  % without the -> operator, call first (this might be very inefficient)
        max2(T,Y),
        H < Y.
    max2([H|T], H):-
        max2(T,Y),
        H >= Y.
    max2([X],X).
    
    
    max3([H|T], Y) :- max_(T,H,Y).            % with helper predicate
    max_([H|T],HighestNow,Highest):-          % call after the test
        (H > HighestNow -> max_(T,H, Highest)
         ;
         max_(T,HighestNow,Highest)).
    max_([],X,X).
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-24
    • 2013-11-16
    • 1970-01-01
    • 2017-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多