Найти максимальное целое число в списке в prolog
Я пытаюсь найти максимальное число в списке. Я знаю, что есть несколько решений, доступных в интернете, но я чувствую, что лучший способ научиться-это реализовать их самостоятельно.
Я написал следующий код:
max([X],X).
max([H|T],Res):-
( H >= Res
-> max(T,Res1), Res1 = H
; max(T,Res)
).
Может ли кто-нибудь указать мне на мою ошибку? Я не в состоянии понять это.2 ответа:
Вы не гарантируете, что
Res
будет создан экземпляр. Для этого вам не обязательно нужен вспомогательный предикат. Вы можете сделать рекурсивный вызов перед проверкой, еслиRes
больше, чемH
, гдеRes
- Самое большое целое числоT
.Вы можете использовать
->
, но вам это не нужно. Но если вы этого не сделаете, то потребуется еще немного отступлений.Если вы попытаетесь остаться больше на вашем маршруте с рекурсией после проверки, вам понадобится вспомогательный предикат, как lurker имеет предложенный.
Edit: поскольку ответ принят сейчас, вот три предложения, реализованные:
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).
Рассмотрим код, представленный в моем ответе на соответствующий вопрос " нахождение максимума в списке - прологе".
Код в упомянутом ответе основан на мета-предикате
Здесь я покажу, как это сделать с метапредикатами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.