Predicate must be true of all elements in a list

2019-08-29 09:54发布

问题:

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?

回答1:

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.


回答2:

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


回答3:

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.


标签: prolog