Пролог: фильтрация списка?
В настоящее время я работаю над очень коротким проектом на Прологе, и просто застрял, пытаясь применить созданный мной "фильтр" к списку. У меня есть то, что вы могли бы назвать фильтром готовым, но я не могу его применить. Было бы лучше, если бы я проиллюстрировал:
filter(A, B)
... выводит true, если соблюдены определенные условия.
filterList(A, [X, Y, Z])
... выводит список, который включает все элементы из второго аргумента, которые делают вывод фильтра ложным. (Таким образом, если фильтр (A, X) имеет значение true, вывод будет [Y, Z]).
У меня есть готовая функция "фильтра", но теперь мне нужно применить ее к списку, как показано во втором примере, за исключением всех элементов, для которых фильтр возвращает true при применении с первым аргументом.
Таким образом, если фильтр является простым A == B, функция должна получать A [A,B,A,C,D,A] и выводить [B,C,D], удалив все элементы, для которых фильтр применяется, очевидно.
У меня возникли проблемы с базовой структурой функции, поэтому, если бы кто-нибудь мог предоставить базовую схему для такой функции, это было бы очень полезно. Я максимально упростил свою ситуацию, чтобы я мог взять все, что вы сможете предоставить, и изменить его для моих нужд.
Заранее спасибо!
6 ответов
Если вы ищете функции более высокого порядка в Прологе, вам обязательно следует обратиться к 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-Пролог имеет =..
оператор, который решает все его проблемы и делает возможной произвольную логику n-порядка.
SWI-Пролог предлагает 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].
Существует неотъемлемая проблема с функциями фильтра, которые рассматривают успех или неудачу предиката в качестве критерия для фильтрации: получающаяся программа больше не является чисто монотонной программой. Поэтому он теряет все свои декларативные свойства - единственное значение, которое остается, - это процедурная пошаговая интерпретация. Вот чистая, усовершенствованная версия фильтрации с использованием 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
, Каждый элемент может быть равным или может отличаться.
Недостатком этого подхода является то, что необходимо предоставить уточненные версии всех критериев.
filter(_,[],[]).
filter(Predicate,[First|Rest],[First|Tail]) :-
filter(Predicate,Rest,Tail).
filter(Predicate,[_|Rest],Result) :-
filter(Predicate,Rest,Result).
Я получаю взрослых людей из страны // Obtengo los Propertos de un pais, Country = 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
Ну, что ты знал, я только что понял это. Итак, вот я и представляю ответ на свой вопрос, как и ожидалось, очень короткая функция справилась со своей задачей:
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.
).