我想在列表中找到最大数字。我知道网上有几种解决方案,但我觉得最好的学习方法是自己实施。
我写了以下代码:
max([X],X).
max([H|T],Res):-
( H >= Res
-> max(T,Res1), Res1 = H
; max(T,Res)
).
有人可以指出我的错误吗?我无法理解。
答案 0 :(得分:2)
考虑my answer中相关问题“Finding the max in a list - Prolog”中提供的代码。
上述答案中的代码基于meta-predicate foldl/4
。
在此,我将展示如何使用元谓词combine/3
和reduce/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/3
和reduce/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
并应用它,直到所有项目合并为一个:
?- 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]. ?- combine(\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)]. ?- combine(\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))]. ?- 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)).
让我们用它来获取列表Max
中的最大整数[1,5,2,4,3,8,7,2]
:
:- use_module(library(clpfd)). ?- reduce(\X^Y^XY^(XY #= max(X,Y)), [1,5,2,4,3,8,7,2], Max). Max = 8. ℅ If you can't use clpfd, simply use is/2 instead of (#=)/2: ?- reduce(\X^Y^XY^(XY is max(X,Y)), [1,5,2,4,3,8,7,2], Max). Max = 8.
答案 1 :(得分:1)
您不能确保Res
被实例化。你不需要辅助谓词来做到这一点。如果Res
大于H
Res
是T
的最大整数,您可以在检查之前进行递归调用。
您可以使用->
,但您不必这样做。但如果你不这样做,就会涉及更多的回溯。
如果您在检查后尝试使用递归更多地保留路线,那么您需要一个辅助谓词,正如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).