I have a set of facts:
likes(john,mary).
likes(mary,robert).
likes(robert,kate).
likes(alan,george).
likes(alan,mary).
likes(george,mary).
likes(harry,mary).
likes(john,alan).
Now I want to write a relation which will check for all element X of an input list if likes(X,A)
is true. my relation should return true once if likes(X,A)
is true for all element X in my list L.
If I try this this:
relat(X) :- member(A,[john,alan,george,harry]), likes(A,X).
but the output is
?- relat(mary).
true ;
true ;
true ;
true.
I want to write it such that it returns one true once it found that likes(john,mary),likes(alan,mary),likes(george,mary),likes(harry,mary)
all are true.
How to approach this problem?
In SWI-Prolog, you can use forall/2
:
?- forall(member(A, [john, alan, george, harry]), likes(A, mary)).
true.
?- forall(member(A, [john,alan,george,harry,marys_ex]), likes(A, mary)).
false.
With standard list processing you can do the following:
helper(X, []). % No one left to check
helper(X, [H|L]) :- likes(H, X), helper(X, L). % Check head, then rest
relat(X) :- helper(X, [john,alan,george,harry]).
Demo:
| ?- relat(harry).
no
| ?- relat(mary).
true ? ;
no
| ?-
Using library(lambda)
:
liked_byall(X, Ps) :-
maplist(X+\P^likes(P,X), Ps).
Equally without lambdas:
liked_byall(X, Ps) :-
maplist(liked(X), Ps).
liked(X, P) :-
likes(P, X).
Equally:
liked_byall(_X, []).
liked_byall(X, [P|Ps]) :-
likes(P, X),
liked_byall(X, Ps).
With above definitions you can ask even more general questions like "Who is liked by certain persons?"
?- liked_byall(N,[john, alan, george, harry]).
N = mary ;
false.
With the following definition these general questions are no longer possible.
liked_byall(X, Ps) :-
\+ ( member(P, Ps), \+ likes(P, X) ).
This second definition only makes sense if X
is ground and Ps
is a ground list. We can ensure this as follows:
liked_byall(X, Ps) :-
( ground(X+Ps) -> true ; throw(error(instantiation_error,_)) ),
length(Ps,_),
\+ ( member(P, Ps), \+ likes(P, X) ).
These extra checks ensure that absurd cases as the following do not succeed:
?- liked_byall(mary, nonlist).
And that otherwise legitimate cases do not produce an incorrect answer:
?- liked_byall(N,[john, alan, george, harry]), N = the_grinch.
N = the_grinch.