Вот что я бы сделал:
foo(A, B, C) :-
select(X, [A, B, C], L1),
select(Y, L1, [Z]),
bar(X, Y),
baz(Z).
Идея состоит в том, что мы будем перетасовывать каждую комбинацию этих параметров, используя select/3
(один из моих любимых предикатов), а затем, переставив их, мы можем просто передать два предиката, которые вам интересны.
Это может быть более понятно, но L2 всегда будет содержать один элемент, поэтому я просто сопоставил его в предыдущем предложении выше:
foo(A, B, C) :-
select(X, [A, B, C], L1),
select(Y, L1, L2),
select(Z, L2, _),
bar(X, Y),
baz(Z).
Редактировать: давайте обработаем произвольное N. Сначала нам понадобится select_n/4
, который даст мне N элементов из списка. Я собираюсь написать это с помощью DCG, потому что мне так проще:
select_n([X|Xs], N) --> select(X), { succ(N0, N) }, select_n(Xs, N0).
select_n([], 0) --> [].
DCG — это не только отличный способ синтаксического анализа текста, но и удобный способ объединения предикатов в строки, которые имеют список ввода и список вывода.
Теперь мы можем использовать этот помощник для создания более общей версии вашего предиката. Допустим, вы берете список для простоты:
foo(L) :-
select_n(BarArgs, 2, L, L1),
select_n(BazArgs, 1, L1, []),
apply(bar, BarArgs),
apply(baz, BazArgs).
Вы можете заменить 2
и 1
выше на все, что хотите, предположительно, исходя из арности bar
и baz
, которую вы хотите вызвать.
Если вы не используете SWI или просто хотите использовать вместо него call/1
, вам придется использовать оператор univ =..
для построения термина перед использованием call/1
:
foo(L) :-
select_n(BarArgs, 2, L, L1),
select_n(BazArgs, 1, L1, []),
Bar =.. [bar|BarArgs],
Baz =.. [baz|BazArgs],
call(Bar),
call(Baz).
person
Daniel Lyons
schedule
18.07.2019