Основной трюк, который вам нужен для этой работы, заключается в том, что вы можете использовать call/N
с различным количеством аргументов.Так что, как только вы сняли X
, Y
и Z
, вы можете получить результат ваших Goal
против них с помощью call(Goal, X, Y, Z, Result)
.
Есть несколько способов сделать это, ноЯ бы предпочел просто составить три списка и повторить все три.Когда самый правый истощен, вы закончили возвращаться.Это дает вам меньше базовых случаев для беспокойства (списки без, один или два элемента не должны обрабатываться отдельно), и нет никаких сокращений, поэтому ваш код будет выглядеть так:
map3(Goal, [X,Y,Z|L], Solutions) :-
map3(Goal, [X,Y,Z|L], [Y,Z|L], [Z|L], Solutions).
map3(_, _, _, [], []).
map3(Goal, [X|XR], [Y|YR], [Z|ZR], [R|Rest]) :-
call(Goal, X, Y, Z, R),
map3(Goal, XR, YR, ZR, Rest).
Это также может быть решено без предиката-помощника, но кое-что оскорбило меня, и это не должно быть намного хуже с точки зрения затрат, так что я пошел по этому пути.
С пустышкойцель foo(X,Y,Z, foo(X,Y,Z))
, я получил этот пример запроса и результата:
?- map3(foo, [a,b,c,d,e,f], Result).
Result = [foo(a, b, c), foo(b, c, d), foo(c, d, e), foo(d, e, f)] ;
false.
Я думаю, что это в основном то, что вы пытаетесь получить, дайте мне знать, если я смогу что-то уточнить.