Prolog: Filtering a list?

我与影子孤独终老i 提交于 2019-12-17 02:24:33

问题


I'm currently working on a very short project on Prolog, and just got stuck trying to apply a "filter" I have created to a list. I have what you could call the filter ready, but I can't apply it. It'd be better if I illustrate:

filter(A, B) 

...outputs 'true' if certain conditions are met.

filterList(A, [X, Y, Z])

...outputs a list which includes all elements from the second argument that make the filter output false. (So if filter(A, X) is true, the output is [Y, Z] ).

I have the "filter" function ready, but now I need to apply it to a list as shown on the second example, excluding all elements for which the filter returns true when applied with the first argument.

So, if the filter is a simple A == B, the function is supposed to receive A [A,B,A,C,D,A] and output [B,C,D], having removed all the elements for which the filter applies, obviously.

I'm having trouble with the basic structure of the function, so if anyone could supply a basic outline for a function such as this it would be of great help. I've simplified my situation as much as possible so I can take whatever you may be able to provide and modify it for my needs.

Thanks in advance!


回答1:


If you are searching for higher-order functions in Prolog, you should definetly consult Naish (1995), a very good resource on this.

His definition of filter/3 is the following (he uses difference-list notation, therefore escapes having to define filter/4):


filter(_,[],[]).
filter(P, A0-As0, As) :-
    (
        call(P, A0) -> As = A0-As1
    ;
        As = As1
    )
    , filter(P, As0, As1).

I you have questions about this predicate, please ask me in the comment. Reading the paper is also highly recommended, it also definess map, foldr and compose! Note that many of the limitations he mentions (like, for example a missing call/3 or a higher-order apply do not apply anymore. SWI-Prolog has the =.. operator, which addresses all of his concerns and makes arbitrary n-order logic possible.




回答2:


SWI-Prolog offers exclude/3 and other such meta-predicates. Your original problem can be coded like this:

are_identical(X, Y) :-
    X == Y.

filterList(A, In, Out) :-
    exclude(are_identical(A), In, Out).

Usage example:

?- filterList(A, [A, B, A, C, D, A], Out).
Out = [B, C, D].



回答3:


There is an inherent problem with filter functions that take the success or failure of a predicate as criterion for filtering: The resulting program is no longer a pure monotonic program. It therefore loses all its declarative properties — the only meaning that remains is a procedural step-by-step interpretation. Here is a pure, reified version of filtering using 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).

The first argument is thus a closure/continuation that will receive two further arguments: The element and the resulting truth value.

=(X,X,true).
=(X,Y,false) :- dif(X,Y).

Now, results remain precise:

| ?- 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

There are four possibilities how a list of two elements can be filtered by the criterion of being equal to X. Each element might be equal or might be different.

The downside of this approach is that one has to provide reified versions of all criteria.




回答4:


Well what'd you know I just figured it out. So, here's me submitting an answer to my own question, as expected a really short function did the job:

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:


I get the adults of a country // Obtengo los adultos 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)

This is a filter in prolog // 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).


来源:https://stackoverflow.com/questions/297996/prolog-filtering-a-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!