How do I use rule in another rule in prolog - 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'].

Related

Combining two lists by summing elements with same indexes does not work

Second day I am trying to make something like this work:
?- sm([1,2,3,4], [3,4,5,6], X).
X = [4,6,8,10].
I have something like this for now:
sm([], []).
sm([Head1|Rest1], [Head2|Rest2], R) :-
ResultElem is Head1 + Head2,
append([ResultElem], R, R1),
sm(Rest1, Rest2, R1).
I get only:
Singleton variables: [X]
false
Why does it not working and how this can finally be overcome?
The problem is that your recursive sm/3 does not have a matching base, because you wrote sm/2 by mistake:
sm([], [], []). /* You forgot the third pair of [] brackets */
As far as the recursive clause goes, it is easier to put the result in the header of the rule, and it lets you avoid using append:
sm([Head1|Rest1], [Head2|Rest2], [ResultElem|R]) :-
ResultElem is Head1 + Head2,
sm(Rest1, Rest2, R).
you can use maplist :
add(X,Y,Z) :-
Z is X+Y.
my_sum(L1, L2, L) :-
maplist(add, L1,L2,L).
With SWI-Prolog and module lambda, you can write
:- use_module(library(lambda)).
my_sum(L1,L2,L) :-
maplist(\X^Y^Z^(Z is X+Y), L1, L2, L).
Finally, with module clpfd, you can have:
:- use_module(library(lambda)).
:- use_module(library(clpfd)).
my_sum(L1,L2,L) :-
maplist(\X^Y^Z^(Z #= X+Y), L1, L2, L).
and we have :
?- my_sum([1,A, 9] ,[B,5,6], [5,7,C]).
A = 2,
B = 4,
C = 15.

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's built-in reverse function acting odd

Given the following code:
fun(a, [b]).
fun(b, [c]).
fun(c, [d]).
fun(d, [e]).
fun(e, []).
xyz(X, Y):-
fun(X,Z) -> findall([A|B], (member(A,Z), xyz(A,B)), L),
flatten(L,F), sort(F,J), reverse(J,Y); Y = [].
With the query xyz(a,X) I get the expected output X = [e,d,c,b]..
What could possibly be throwing this off? Does this have to do with the sort function? If so, according to the documents in the links below, alpha or numeric order of precedence could be throwing this off, but it still doesn't explain by cs40 is going before cs30. I am having a hard time finding a correlation. How can I fix this issue?
http://www.swi-prolog.org/pldoc/doc_for?object=sort/2
http://www.swi-prolog.org/pldoc/man?section=compare
By the way, the fun function could have multi-element lists such as fun(a, [b,c], where a has multiple dependencies b and c. This aspect shouldn't matter too much regarding the current issue that I have, but just getting this fact out there.
UPDATE
Thanks to #lurker, I've made some great progress.
Given the following code:
final_xyz(X, Y):- xyz(X, R), reverse(R, Y).
xyz(X, Y) :-
fun(X,Z) -> findall([A|B], (member(A,Z), xyz(A,B)), L),
flatten(L,Y); Y = [].
In an attempt to fix this, I updated the code to:
xyz-final(X,Y):-
fun(X,Z),
Z\=0,
( length(Z,1) -> xyz(X,J), reverse(J,Y)
;
xyz2(X,B), sort(B,C), reverse(C,Y)
).
xyz(K, [X|Y]):- fun(K, [X]), !, xyz(X, Y).
xyz(_, []).
xyz2(X, Y) :-
fun(X,Z) -> findall([A|B], (member(A,Z), xyz2(A,B)), L),
flatten(L,Y); Y = [].
Very clumsy approach, but this seems to work for me now. I'll work on making it more efficient.
The issue is that you are wanting to reverse the final result, but your reverse is being done in each recursive call to xyz/2. If you do a trace on your xyz(cs140a, X) call, you'll see it's being called a few times on different recursions.
If you want it once at the end, then you can write it this way:
final_xyz(X, Y) :-
xyz(X, R),
reverse(R, Y).
xyz(X, Y) :-
fun(X,Z) -> findall([A|B], (member(A,Z), xyz(A,B)), L),
flatten(L,Y); Y = [].
And then calling final_xyz(cs140a, X) yields, X = [m16a,cs30,cs40,cs110].
Here's an alternative approach to your xyz predicate which avoids the findall and the flatten. This version should avoid cyclical paths and doesn't show duplicates:
xyz(X, Y) :-
fun(X, L),
xyz(L, [], R),
reverse(R, Y).
xyz([H|T], A, R) :-
( memberchk(H, A)
-> xyz(T, A, R)
; fun(H, L)
-> xyz(L, [H|A], R1),
xyz(T, R1, R)
; xyz(T, [H|A], R)
).
xyz([], A, A).

Predicate must be true of all elements in a list

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.

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