Обычно используется так называемый «запаздывающий аргумент», чтобы извлечь выгоду из индексации первого аргумента:
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
, доступный в последних версиях SWI, позволяет записать его как:
list_min([L|Ls], Min) :- foldl(num_num_min, Ls, L, Min).
num_num_min(X, Y, Min) :- Min is min(X, Y).
Обратите внимание, что это не может быть использовано во всех направлениях, например:
?- list_min([A,B], 5).
is/2: Arguments are not sufficiently instantiated
Если вы рассуждаете о целых числах , как, кажется, имеет место в вашем примере, я рекомендую вам использовать ограничения CLP (FD) для естественного обобщения предиката. Вместо (is)/2
просто используйте (#=)/2
и воспользуйтесь более декларативным решением:
:- use_module(library(clpfd)).
list_min([L|Ls], Min) :- foldl(num_num_min, Ls, L, Min).
num_num_min(X, Y, Min) :- Min #= min(X, Y).
Это можно использовать как истинное отношение, которое работает во всех направлениях, например:
?- list_min([A,B], 5).
получают:
A in 5..sup,
5#=min(B, A),
B in 5..sup.