General_9
General_9

Reputation: 2319

Prolog filter a list of all elements for which a custom goal fails

I am trying to write a predicate filter(List, PredName, Result) that filters a List of all its elements for which the goal PredName fails and subsequently returns the Result list. The predicate PredName/1 should be defined when calling the procedure filter/3 and could for example be:

test(N) :- N >= 0

A query could then be made like following:

?- filter([-6,7,-1,0], test, L)
L = [7, 0];
no

Upvotes: 3

Views: 1777

Answers (3)

Gökhan Uras
Gökhan Uras

Reputation: 181

One way to do that is using recursion and the call/2 predicate

filter([],_,[]).
filter([H|T], PredName, [H|S]) :-  call(PredName,H),filter(T,PredName,S),!.
filter([H|T], PredName, S) :- filter(T,PredName,S).

The other way to that is, instead of using call/2, you can use =.. (univ) operator.

filter([],_,[]).
filter2([H|T], PredName, [H|S]) :-  Goal =.. [PredName,H],Goal,filter(T,PredName,S),!.
filter([H|T], PredName, S) :- filter(T,PredName,S).

The =.. operator takes a list that contains predicate name and its arguments and returns newly created term. for example:

?-X =.. [f,a,b].
X = f(a, b).

Upvotes: -1

Nick Main
Nick Main

Reputation: 1450

If you are using SWI-Prolog you could use the exclude predicate from the "apply" library

Upvotes: 3

DaveEdelstein
DaveEdelstein

Reputation: 1256

I'm sure a builtin operation exists to do this... but essentially you are just trying to do a findall on the member of the list that pass the predicate. Try this implementation of filter out. The second arg to findall is run until all results are exhausted and all values of M are collected into Result.

filter(List,PredName,Result) :-
  findall(M, ( member(M, List), call(PredName,M)), Result).

Upvotes: 1

Related Questions