Predicate must be true of all elements in a list - prolog

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.

Related

Prolog query doesn't work for some reason

I'm trying to write a simple game in Prolog. And here is my predicate for inventory:
:- dynamic have/1.
inv(0, []).
inv(N, [X | Rest]):- have(X),
\+ member(X, Rest),
N1 is N - 1,
inv(N1, Rest).
So, I'm trying to choose every item which player has, and it works for this for example
?- inv(2, [classic_gun, medkit]).
true .
but for inv(2, R) I get false.
?- inv(2, R).
false.
What did I do wrong?

How do I use rule in another rule in prolog

Here are my facts:
object('Human').
object('Machine').
object('Robot').
object('Hunter').
object('WallE').
action('Kill').
action('Run').
rel1('Hunter', 'Human').
rel1('Robot', 'Machine').
rel1('WallE', 'Robot').
rel2('Human', 'Run').
rel2('Machine', 'Run').
rel2('Robot', 'Kill').
I'm trying to find the list of all object that implement a given action. So for example if I run this:
?-provides_action(’Run’, X).
It gives the result:
X = [’Human’, ’Machine’, ’Hunter’, ’Robot’, ’WallE’].
OR
?-provides_action(’Kill’, X).
It gives the result:
X = ['WallE'].
I have tried this
provides_action2(X, L) :- findall(Y, (rel2(Y,X)),L).
provides_action3(X, L) :- provides_action2(X, L1), findall(Z, rel1(Z,L1), L2), append(L1,L2,L).
It doesnt give me the correct answer, I want to use the result from the first rule (L1) and use it in the 2nd findall extends(Z,L1) but it doesnt seem to do that.
Could anyone please explain to me what's wrong?
Thank you in advance!
First, you must define predicate extends/2 using rel1/2:
extends(A, C) :- rel1(A, C).
extends(A, C) :- rel1(A, B), extends(B, C).
Examples:
?- extends(X, 'Human').
X = 'Hunter' ;
false.
?- extends(X, 'Machine').
X = 'Robot' ;
X = 'WallE' ;
false.
After, you can use this predicate to define provides_action/2, as following:
provides_action(X, L) :-
findall(Y, rel2(Y,X), L1),
findall(C, (member(A, L1), extends(C, A)), L2),
append(L1, L2, L).
Notice that member(A, L1) is needed to iterate list L1.
Running example:
?- provides_action('Run', L).
L = ['Human', 'Machine', 'Hunter', 'Robot', 'WallE'].

Pure Prolog Meta-Interpreter with one Rule

I wonder whether there is a pure Prolog meta-interpreter with
only one rule. The usual Prolog vanilla meta-interpreter has two
rules. It reads as follows:
solve(true).
solve((A, B)) :- solve(A), solve(B). /* rule 1 */
solve(H) :- program(H, B), solve(B). /* rule 2 */
This Prolog vanilla meta-interpreter uses two rules /* rule 1 */
and /* rule 2 */. And the rest is facts. The program that
is executed is represented by program facts. Here is an example program:
program(append([], X, X), true).
program(append([X|Y], Z, [X|T]), append(Y, Z, T)).
program(nrev([], []), true).
program(nrev([H|T], R), (nrev(T, S), append(S, [H], R))).
And an example query:
?- solve(nrev([1,2,3], X)).
X = [3, 2, 1] .
Is there a way to represent the program differently as facts, and
then code a different meta-interpreter, which would use only facts
except for a single rule instead of two rules? Something that would
work for all pure Prolog programs, not only the nrev example?
Here is one idea, using a list to hold the rest of the computation:
solve([]).
solve([X|Xs]) :- program(X, Ys, Xs), solve(Ys).
program(true, Xs, Xs).
program(append([],X,X), Xs, Xs).
program(append([X|Y], Z, [X|T]), [append(Y,Z,T)|Xs], Xs).
program(nrev([],[]), Xs, Xs).
program(nrev([H|T],R), [nrev(T,S),append(S,[H],R)|Xs], Xs).
With test call (where one needs to wrap the call in a list).
?- solve([nrev([1,2,3],X)]).
X = [3,2,1] ? ;
no
Arguably, one could represent the program/3 facts as a DCG instead, for increased readability (but then it might not be considered a "fact" any more).
Here is another approach, known as binarization with continuation.
Its from this logic transformers paper here by Paul Tarau (2021).
solve(true).
solve(X) :- program(X, Y), solve(Y).
program(append([],X,X,C), C).
program(append([X|Y],Z,[X|T],C), append(Y,Z,T,C)).
program(nrev([],[],C), C).
program(nrev([H|T],R,C), nrev(T,S,append(S,[H],R,C))).
A little sanity check shows that it wurks:
?- solve(nrev([1,2,3], X, true)).
X = [3, 2, 1] ;
No
If ;/2 is allowed, then this seems to work:
solve(true).
solve(H) :- ((X, Y) = H, solve(X), solve(Y)); (program(H :- B), solve(B)).
program(append([], X, X) :- true).
program(append([X|Y], Z, [X|T]) :- append(Y, Z, T)).
program(nrev([], []) :- true).
program(nrev([H|T], R) :- (nrev(T, S), append(S, [H], R))).
Test:
?- solve(nrev([1,2,3], X)).
X = [3, 2, 1] ;
false.

Write a Prolog predicate next(X,List,List1)

Prolog predicate next(X, List,List1), that returns in List1 the next element(s) from List that follows X, e.g., next(a,[a,b,c,a,d],List1), will return List1=[b,d].
I have tried following:
next(X, [X,Y|List], [Y|List1]) :- % X is the head of the list
next(X, [Y|List], List1).
next(X, [Y|List], List1) :- % X is not the head of the list
X \== Y,
next(X, List, List1).
next(_,[], []).
First, whenever possible, use prolog-dif for expressing term inequality!
Second, the question you asked is vague about corner cases: In particular, it is not clear how next(E,Xs,Ys) should behave if there are multiple neighboring Es in Xs or if Xs ends with E.
That being said, here's my shot at your problem:
next(E,Xs,Ys) :-
list_item_nexts(Xs,E,Ys).
list_item_nexts([],_,[]).
list_item_nexts([E],E,[]).
list_item_nexts([I|Xs],E,Ys) :-
dif(E,I),
list_item_nexts(Xs,E,Ys).
list_item_nexts([E,X|Xs],E,[X|Ys]) :-
list_item_nexts(Xs,E,Ys).
Let's see some queries!
?- next(a,[a,b,c,a,d],List1).
List1 = [b,d] ;
false.
?- next(a,[a,a,b,c,a,d],List1).
List1 = [a,d] ;
false.
?- next(a,[a,a,b,c,a,d,a],List1).
List1 = [a,d] ;
false.
Note that above queries succeed, but leave behind useless choicepoints.
This inefficiency can be dealt with, but I suggest figuring out more complete specs first:)
This version is deterministic for the cases given by #repeat using if_/3 and (=)/3. It shows how purity and efficiency can coexist in one and the same Prolog program.
next(E, Xs, Ys) :-
xs_e_(Xs, E, Ys).
xs_e_([], _E, []).
xs_e_([X|Xs], E, Ys) :-
if_(X = E, xs_e_xys(Xs, E, Ys), xs_e_(Xs, E, Ys)).
xs_e_xys([], _E, []).
xs_e_xys([X|Xs], E, [X|Ys]) :-
xs_e_(Xs, E, Ys).
%xs_e_xys([X|Xs], E, [X|Ys]) :- % alternate interpretation
% xs_e_([X|Xs], E, Ys).

Prolog ERROR out of global stack

ass(a).
ass(b).
ass(c).
con(c,r).
arg(A, L) :- forall(member(S, L), (ass(S), \+ con(S,A))).
If I run arg(r, [a,b]) it will work but if I run arg(r,X) it returns: ERROR out of global stack. I would like it to return [a,b]. I understand this is because L is unbounded, but how can I fix this.
In the predicate:
arg(A, L) :- forall(member(S, L), (ass(S), \+ con(S,A))).
May have a limitation in your case as described in the SWI Prolog documentation for forall/2:
If your intent is to create variable bindings, the forall/2 control
structure is inadequate. Possibly you are looking for maplist/2,
findall/3 or foreach/2.
So in this case, you may be better off with:
arg(A, L) :- findall(S, (ass(S), \+ con(S,A)), L).
Which will yield:
?- arg(r, X).
X = [a, b].
?- arg(r, [a,b]).
true.
?-

Resources