В дополнение к другим опубликованным версиям рассмотрим также версию без if-then-else и с использованием более описательного имени для отношения (которое связывает список с его минимумом):
list_min([L|Ls], Min) :- list_min(Ls, L, Min).
list_min([], Min, Min).
list_min([L|Ls], Min0, Min) :-
Min1 is min(L, Min0),
list_min(Ls, Min1, Min).
Такой шаблон называется fold (слева), и мы можем написать его эквивалентно, используя `foldl / 4:
list_min([L|Ls], Min) :- foldl(min_, Ls, L, Min).
min_(A, B, Min) :- Min is min(A, B).
Пример запроса:
?- list_min([1,0,2], Min).
Min = 0.
Обратите внимание, что это не является истинным отношением и не может использоваться во всех направлениях из-за использования низкоуровневой арифметики.Например, если мы попытаемся использовать его в другом направлении, мы получим:
?- list_min([X,Y], 3).
<b>ERROR: is/2</b>: Arguments are not sufficiently instantiated
Чтобы сделать его истинным решением, используйте ограничений подобно clpfd и clpq .Например, для решения свыше целых чисел :
:- use_module(library(clpfd)).
list_min([L|Ls], Min) :- foldl(min_, Ls, L, Min).
min_(A, B, Min) :- Min #= min(A, B).
Это работает во всех направлениях:
?- list_min([X,Y], 3).
X in 3..sup,
3#=min(Y, X),
Y in 3..sup.