JavaDumbell
JavaDumbell

Reputation: 235

Prolog: Filtering a list of goals and keeping the successful goals

Giving the following facts and restriction :

car(red, 2000).
car(black, 1990).
car(blue, 2010).

millennials(car(_,Y)) :- (car(_,Y)), Y =< 1995.
red(car(C,_)) :- car(C,_), C == red.

Given a list [millennials, red], I would like to make a call such as:

checkRestriction([millennials, red], car(red, 2000) , L).
L = red

Which return a list of the conditions that are respected by the car passed as argument.

This is different from this thread: How to filter a list in Prolog with multiple conditions?, because all restriction don't have to be successful, the goal is only to return a list of successful restriction with the car passed as argument.

I tried the following:

checkRestriction([],_,[]).
checkRestriction([H|T], Car, List) :-
   (    H(Car) 
   ->   append(L, H(Car), List), 
        checkRestriction(T, Car, List) 
   ;    checkRestriction(T, Car, List) ).

Which check is the restriction returns true with car as argument, and append in that case to a list the restriction itself, otherwise is simply call the predicate with the tail of the list, but I get compilation error.

Upvotes: 1

Views: 74

Answers (2)

slago
slago

Reputation: 5509

The goal H(Car) causes a compilation error because a variable cannot be used as predicate name in Prolog. To correct your code, you must construct goal terms as follows:

?- H = red, Car = car(red,2000), Goal =.. [H,Car].
H = red,
Car = car(red, 2000),
Goal = red(car(red, 2000)).

?- H = millennials, Car = car(red,2000), Goal =.. [H,Car].
H = millennials,
Car = car(red, 2000),
Goal = millennials(car(red, 2000)).

Thus, the correct code is:

checkRestriction([], _, []).
checkRestriction([H|T], Car, Result) :-
    Goal =.. [H, Car],
    (   call(Goal)
    ->  Result = [H|List],
        checkRestriction(T, Car, List)
    ;   checkRestriction(T, Car, Result) ).

millennials(car(_,Y)) :- car(_,Y), Y =< 1995.

red(car(C,_)) :- car(C, _), C == red.
blue(car(C,_)) :- car(C, _), C == blue.
black(car(C,_)) :- car(C, _), C == black.

Running examples:

?- checkRestriction([millennials, red], car(red,2000), L).
L = [red].

?- checkRestriction([millennials, black], car(black,1990), L).
L = [millennials, black].

?- checkRestriction([millennials, blue], car(blue,2010), L).
L = [blue].

?- checkRestriction([millennials, black], car(blue,2010), L).
L = [].

Alternatively, you can use call/N:

checkRestriction([], _, []).
checkRestriction([H|T], Car, Result) :-
    (   call(H, Car)
    ->  Result = [H|List],
        checkRestriction(T, Car, List)
    ;   checkRestriction(T, Car, Result) ).

Upvotes: 1

Peter Ludemann
Peter Ludemann

Reputation: 1005

See the include/3 predicate in library(apply). https://www.swi-prolog.org/pldoc/doc/_SWI_/library/apply.pl?show=src

Upvotes: 0

Related Questions