SWI-Prolog offers library(aggregate). Generalized and performance wise.
:- [library(aggregate)].
min(L, M) :- aggregate(min(E), member(E, L), M).
edit
A recent addition was library(solution_sequences). Now we can write
min(L,M) :- order_by([asc(M)], member(M,L)), !.
max(L,M) :- order_by([desc(M)], member(M,L)), !.
Now, ready for a surprise :) ?
?- test_performance([clpfd_max,slow_max,member_max,rel_max,agg_max]).
clpfd_max:99999996
% 1,500,000 inferences, 0.607 CPU in 0.607 seconds (100% CPU, 2470519 Lips)
slow_max:99999996
% 9,500,376 inferences, 2.564 CPU in 2.564 seconds (100% CPU, 3705655 Lips)
member_max:99999996
% 1,500,009 inferences, 1.004 CPU in 1.004 seconds (100% CPU, 1494329 Lips)
rel_max:99999996
% 1,000,054 inferences, 2.649 CPU in 2.648 seconds (100% CPU, 377588 Lips)
agg_max:99999996
% 2,500,028 inferences, 1.461 CPU in 1.462 seconds (100% CPU, 1710732 Lips)
true
with these definitions:
```erlang
:- use_module(library(clpfd)).
clpfd_max([L|Ls], Max) :- foldl([X,Y,M]>>(M #= max(X, Y)), Ls, L, Max).
slow_max(L, Max) :-
select(Max, L, Rest), \+ (member(E, Rest), E @> Max).
member_max([H|T],M) :-
member_max(T,N), ( \+ H@<N -> M=H ; M=N ).
member_max([M],M).
rel_max(L,M) :-
order_by([desc(M)], member(M,L)), !.
agg_max(L,M) :-
aggregate(max(E), member(E,L), M).
test_performance(Ps) :-
test_performance(Ps,500 000,_).
test_performance(Ps,N_Ints,Result) :-
list_of_random(N_Ints,1,100 000 000,Seq),
maplist({Seq}/[P,N]>>time((call(P,Seq,N),write(P:N))),Ps,Ns),
assertion(sort(Ns,[Result])).
list_of_random(N_Ints,L,U,RandomInts) :-
length(RandomInts,N_Ints),
maplist({L,U}/[Int]>>random_between(L,U,Int),RandomInts).
clpfd_max wins hands down, and to my surprise, slow_max/2 turns out to be not too bad...