Пролог: Фильтрация списка?
В настоящее время я работаю над очень коротким проектом Prolog и просто застрял, пытаясь применить "фильтр", который я создал в списке. У меня есть то, что вы могли бы назвать фильтром готовым, но я не могу его применить. Было бы лучше проиллюстрировать:
filter(A, B)
... выводит "true", если выполняются определенные условия.
filterList(A, [X, Y, Z])
... выводит список, содержащий все элементы из второго аргумента, которые делают выходной фильтр false. (Таким образом, если фильтр (A, X) истинен, выходной сигнал [Y, Z]).
У меня есть функция "фильтр", но теперь мне нужно применить ее к списку, как показано на втором примере, за исключением всех элементов, для которых фильтр возвращает true при применении с первым аргументом.
Итак, если фильтр является простым A == B, функция должна получать A [A, B, A, C, D, A] и выводить [B, C, D], удалив все элементы, для которых фильтр применяется, очевидно.
У меня возникают проблемы с базовой структурой функции, поэтому, если кто-то может предоставить базовый план для такой функции, как это, это будет очень полезно. Я упростил ситуацию настолько, насколько это возможно, поэтому я могу взять все, что вы можете предоставить и изменить для моих нужд.
Спасибо заранее!
Ответы
Ответ 1
Если вы ищете функции более высокого порядка в Прологе, вам обязательно следует обратиться к Naish (1995), очень хорошему источнику по этому вопросу.
Его определение filter/3
следующее (он использует нотацию списка различий, поэтому избегает необходимости определять filter/4
):
filter(_,[],[]).
filter(P, A0-As0, As) :-
(
call(P, A0) -> As = A0-As1
;
As = As1
)
, filter(P, As0, As1).
Если у вас есть вопросы по этому предикату, пожалуйста, спросите меня в комментарии. Чтение бумаги также настоятельно рекомендуется, это также бросает вызов map
, foldr
и compose
! Следует отметить, что многие из ограничений, которые он упоминает (как, например, отсутствует call/3
или более высокого порядка, apply
не применяются больше. SWI-Prolog имеет =..
оператор, который адресует все его проблемы и делает произвольную N- Логика заказа возможна.
Ответ 2
SWI-Prolog предлагает exclude/3
и другие подобные мета-предикаты. Ваша исходная проблема может быть закодирована следующим образом:
are_identical(X, Y) :-
X == Y.
filterList(A, In, Out) :-
exclude(are_identical(A), In, Out).
Пример использования:
?- filterList(A, [A, B, A, C, D, A], Out).
Out = [B, C, D].
Ответ 3
Существует неотъемлемая проблема с функциями фильтра, которые используют успех или неудачу предиката в качестве критерия фильтрации: результирующая программа больше не является чистой монотонной программой. Поэтому он теряет все свои декларативные свойства; единственное значение, которое остается, является процедурной поэтапной интерпретацией. Вот чистая, перезаработанная версия фильтрации с помощью if_/3
:
tfilter(_CT_2, [], []).
tfilter(CT_2, [E|Es], Fs0) :-
if_(call(CT_2,E), Fs0 = [E|Fs], Fs0 = Fs ),
tfilter(CT_2, Es, Fs).
Таким образом, первым аргументом является замыкание/продолжение, которое получит еще два аргумента: Элемент и результирующее значение истины.
=(X,X,true).
=(X,Y,false) :- dif(X,Y).
Теперь результаты остаются точными:
| ?- tfilter(=(X),[A,B],Xs).
B = A,
X = A,
Xs = [A,A] ? ;
X = A,
Xs = [A],
dif(A,B) ? ;
X = B,
Xs = [B],
dif(B,A) ? ;
Xs = [],
dif(X,A),
dif(X,B) ? ;
no
Существует четыре возможности, по которым можно фильтровать список из двух элементов по критерию равным X
. Каждый элемент может быть равен или может отличаться.
Недостатком этого подхода является то, что нужно предоставить обновленные версии всех критериев.
Ответ 4
Хорошо, что ты знаешь, я просто понял это. Итак, здесь я отправляю ответ на свой вопрос, как и ожидалось, действительно короткая функция выполняла работу:
filterList(_,[],R,R). % Returns answer when the list is exhausted.
filterList(L,[A|List],Temp,Res) :-
filterList(L,List,New,Res), % Recursive call, New is either the same list
( filter(L,A), % in case the filter outputs true, or the list
New = Temp
; New = [A|Temp] % plus the current element otherwise.
).
Ответ 5
Я получаю взрослых в стране //Obtengo los adultos de un pais, Страна = Pais, People = Personas, Person = una sola Persona
habitants(USA, [juan, pedro, david])
adults(Adults, Country) :-
findall(Person, (habitants(Country,People), member(People, Person), adult(Person)), Adults)
Это фильтр в прологе //Asi es un filter en prolog
Ответ 6
filter(_,[],[]).
filter(Predicate,[First|Rest],[First|Tail]) :-
filter(Predicate,Rest,Tail).
filter(Predicate,[_|Rest],Result) :-
filter(Predicate,Rest,Result).