Возможно, вам не поможет решение, которое не использует append/3
. Например, рассмотрим следующий предикат filter/3
:
filter(_Pattern, [], []).
filter(Pattern, [E|Es], Matches) :-
Pattern \= E, !,
filter(Pattern, Es, Matches).
filter(Pattern, [E|Es], [E|Matches]) :-
filter(Pattern, Es, Matches).
Первое предложение filter/3
является базовым случаем, где, если во втором списке аргументов нет ничего, что можно сопоставить, мы получаем пустой список. Поскольку мы не учитывали Pattern
, он игнорируется (отсюда и предыдущий _
против переменной).
Во втором предложении filter/3
проверяется, может ли Pattern
, который может быть связан с термином (например, foo(X,Y)
), объединять с первым элементом списка для сопоставления E
. Оператор \=
будет успешным, когда его аргументы не могут быть объединены , поэтому, если это удастся, когда мы не сопоставим E
с шаблоном, он может выбросить его и продолжить (обратите внимание на сокращение !
после теста для фиксации в этой ветке).
Последнее (третье) предложение filter/3
зависит от второго предложения, поскольку оно просто передает E
в список последних аргументов Matches
, предполагая, что равно совпадению с Pattern
, поскольку в предыдущем пункте не удалось определить, что не совпадение. Обратите внимание, что мы добавляем E
к списку, привязывая структуру списка к выводу, оставляя подсписок Matches
свободным; полный список Matches
будет полностью связан только тогда, когда он достигнет базового случая, связывая его с пустым списком []
, когда у нас закончатся термины для сопоставления во втором аргументе, создавая что-то вроде [E1,E2,...,En|[]]
, где каждый E1
до En
соответствует шаблону; этот термин эквивалентен списку [E1,E2,...,En]
.
Проверка этого предиката следующим образом дает:
?- filter(foo(X,Y), [a,b,foo(x,y),c(f),foo(v(3),Z),5], L).
L = [foo(x, y), foo(v(3), Z)] ;
false.
Обратите внимание, что здесь все, что можно отнести к шаблону foo(X,Y)
, было отфильтровано в L
при необходимости.
Последнее замечание: в вашем коде вызов append(foo(X,Y),R,L)
всегда будет неудачным, поскольку append/3
работает только со списками; вы, вероятно, хотели бы вместо этого позвонить append([foo(X,Y)],R,L)
, но в этом случае вы просто используете вместо него L = [foo(X,Y)|R]
.
РЕДАКТИРОВАТЬ: Чтобы соответствовать вашему конкретному случаю, когда у вас есть список возможных шаблонов для сопоставления и фильтрации, вот еще один предикат, filter_list/3
:
filter_list(_Patterns, [], []).
filter_list(Patterns, [E|Es], Matches) :-
filter(E, Patterns, []), !,
filter_list(Patterns, Es, Matches).
filter_list(Patterns, [E|Es], [E|Matches]) :-
filter_list(Patterns, Es, Matches).
Обратите внимание, что filter_list/3
зависит от моего предыдущего определения filter/3
и реализовано с использованием точно такой же стратегии: если E
не соответствует ни одному из Patterns
(т. Е. Это тот случай, когда filter(E, Patterns, [])
успешно), затем мы забываем E
и продолжаем, иначе (последнее предложение) мы сохраняем его. Тестирование дает нам:
?- filter_list([foo(X,Y),bar(X),b], [a,b,foo(X,Y),c], L).
L = [b, foo(X, Y)] ;
false.