Can delay using when
:
list_min_max_len(MinLen, MaxLen, Lst) :-
when(nonvar(MinLen), (
MinLen @>= 0,
ensure_min_len(MinLen, Lst)
)),
when((nonvar(MinLen), nonvar(MaxLen)), (
MaxLen @>= MinLen
)),
when(nonvar(MaxLen),
max_len_freeze(Lst, 0, MaxLen)
).
max_len_freeze([], Upto, MaxLen) :-
Upto == MaxLen,
% At max len, so avoid [H|T]
!.
max_len_freeze([], Upto, MaxLen) :-
Upto @< MaxLen.
max_len_freeze([_|T], Upto, MaxLen) :-
Upto1 is Upto + 1,
compare(Comp, MaxLen, Upto1),
max_len_freeze_next_(Comp, T, Upto1, MaxLen).
max_len_freeze_next_(=, [], Upto, MaxLen) :-
max_len_freeze([], Upto, MaxLen).
max_len_freeze_next_(>, T, Upto, MaxLen) :-
when(nonvar(T), max_len_freeze(T, Upto, MaxLen)).
ensure_min_len(MinLen, Lst) :-
compare(Comp, MinLen, 0),
ensure_min_len_(Comp, Lst, MinLen).
ensure_min_len_(=, _, 0).
ensure_min_len_(>, [_|T], MinLen) :-
MinLen0 is MinLen - 1,
compare(Comp, MinLen0, 0),
ensure_min_len_(Comp, T, MinLen0).
Results in swi-prolog:
?- list_min_max_len(Min, Max, L), L = [a,b,c|T], Max = 3, Min = 3.
L = [a, b, c],
Min = Max, Max = 3,
T = [].
?- list_min_max_len(Min, Max, L), L = [a,b,c|T], Min = 5.
L = [a, b, c, _A, _B|_C],
Min = 5,
T = [_A, _B|_C],
when(nonvar(Max), max_len_freeze([a, b, c, _A, _B|_C], 0, Max)),
when(nonvar(Max), Max@>=5).
% Prevents length/2 from going to infinity, if MaxLen is specified first
?- list_min_max_len(Min, Max, L), L = [a,b,c|T], Min = 2, Max = 5, length(L, Len).
L = [a, b, c],
Min = 2,
Max = 5,
T = [],
Len = 3 ;
L = [a, b, c, _A],
Min = 2,
Max = 5,
T = [_A],
Len = 4 ;
L = [a, b, c, _A, _B],
Min = 2,
Max = Len, Len = 5,
T = [_A, _B].
% Beware - can't magically rein in length/2
?- list_min_max_len(Min, Max, L), Min = 2, L = [a,b,c|T], length(L, Len), Max = 3.
L = [a, b, c],
Min = 2,
Max = Len, Len = 3,
T = [] ;
<length/2 goes to infinity>