Учитывая, что никто не ответил, и прошло довольно много времени с тех пор, как я написал что-то на Прологе и решил, что мне нужна практика, вот как вы это сделаете.
Во-первых, чтобы упростить создание комбинаций, мы создаем термин для предварительной обработки списков, чтобы связать их с их длинами, чтобы избежать необходимости многократного получения длин. Срез избегает ненужного возврата:
with_lengths([], []) :- !.
with_lengths([H|T1], [(Len, H)|T2]) :-
length(H, Len),
with_lengths(T1, T2).
Вот предикат comb/3
, который вы используете для генерации комбинаций:
comb(L, R, Max) :-
with_lengths(L, L1),
comb1(L1, R, Max).
comb1/3
выполняет реальную работу. Комментарии объясняют, что происходит:
% Combination works.
comb1([], [], 0).
% Try combining the current element with the remainder.
comb1([(Len, Elem)|T1], [Elem|T2], Max) :-
NewMax is Max - Len,
comb1(T1, T2, NewMax).
% Alternatively, ignore the current element and try
% combinations with the remainder.
comb1([_|T1], T2, Max) :-
comb1(T1, T2, Max).