How to create a list from facts in Prolog? - prolog

There are these facts:
man(john).
man(carl).
woman(mary).
woman(rose).
I need to create the predicate people(List), which returns a list with the name of every man and woman based on the previous facts. This is what I need as output:
?- people(X).
X = [john, carl, mary, rose]
And here is the code I wrote, but it's not working:
people(X) :- man(X) ; woman(X).
people(X|Tail) :- (man(X) ; woman(X)) , people(Tail).
Could someone please help?

Using findall/3:
people(L) :- findall(X, (man(X) ; woman(X)), L).
?- people(X).
X = [john, carl, mary, rose].

Here we go:
person(anne).
person(nick).
add(B, L):-
person(P),
not(member(P, B)),
add([P|B], L),!.
add(B, L):-
L = B,!.
persons(L):-
add([], L).

Related

How to find Nephew in Prolog Family Code?

I'm trying to get Prolog to output people in the family trees nephew, as in nephew(X,Y) will list
X = the nephew
Y = Aunt/ Uncle
I've tried writing some of the code already, I'm pretty confident the son command works, and I believe sibling works, however combining these is proving, difficult.
parent(pam,bob).
parent(john,bob).
parent(john,liz).
parent(bob,ann).
parent(bob,pat).
parent(pat,jim).
parent(liz,joe).
parent(liz,tim).
parent(joe,kim).
female(pam).
female(liz).
female(ann).
female(pat).
female(zoe).
female(kim).
male(bob).
male(john).
male(jim).
male(joe).
male(tim).
sibling(X, Y) :- parent(Z, X), parent(Z, Y), X \= Y.
son(X,Y) :- parent(Y, X), male(X).
nephew(X, Y) :- sibling(Y, Z), son(Z, X).
You were so close.
If you ran your query
nephew(X,Y) you would get
?- nephew(X,Y).
X = pam,
Y = liz ;
X = john,
Y = liz ;
X = liz,
Y = joe ;
X = liz,
Y = tim ;
false.
which as you note is wrong.
However if you rename your variables so that they are easier to comprehend
sibling(Child_a, Child_b) :-
parent(Parent, Child_a),
parent(Parent, Child_b),
Child_a \= Child_b.
son(Child,Parent) :-
parent(Parent, Child),
male(Child).
nephew(Parent, Child_a) :-
sibling(Child_a, Child_b),
son(Child_b, Parent).
you will see that sibling/2 and son/2 are correct and should see your problem with nephew/2.
When renaming variables, start at the facts and work back, do not start at the head of a clause and work down.
Another way that helps to figure out problems with multi-statement predicates is to run parts of them as separate queries, e.g.
?- sibling(Parent,Aunt_uncle),son(Nephew,Parent).
Parent = liz,
Aunt_uncle = bob,
Nephew = joe ;
Parent = liz,
Aunt_uncle = bob,
Nephew = tim ;
Parent = pat,
Aunt_uncle = ann,
Nephew = jim ;
false.
While this query gives more information than is needed, the correct values are in the results. Putting this in a predicate and returning only the desired values is all that is left to get this query working as desired.
A correct answer for nephew/2 is
nephew(Nephew,Aunt_uncle) :-
sibling(Parent,Aunt_uncle),
son(Nephew,Parent).
Example run:
?- nephew(Nephew,Aunt_uncle).
Nephew = jim,
Aunt_uncle = ann ;
Nephew = joe,
Aunt_uncle = bob ;
Nephew = tim,
Aunt_uncle = bob ;
false.
When writing code it is advisable to also create test cases.
If you are using SWI-Prolog then you can use the following test cases.
:- begin_tests(family).
% example of single test case
test(001) :-
sibling(bob,liz).
test(002) :-
son(tim,liz).
test(003,[nondet]) :-
nephew(tim,bob).
% example of test cases that test multiple variations for one predicate
sibling_test_case(bob,liz).
sibling_test_case(liz,bob).
sibling_test_case(ann,pat).
sibling_test_case(pat,ann).
sibling_test_case(joe,tim).
sibling_test_case(tim,joe).
test(004, [forall(sibling_test_case(Child_a,Child_b))]) :-
sibling(Child_a,Child_b).
son_test_case(bob,pam).
son_test_case(bob,john).
son_test_case(jim,pat).
son_test_case(joe,liz).
son_test_case(tim,liz).
test(005, [forall(son_test_case(Child,Parent)),nondet]) :-
son(Child,Parent).
nephew_test_case(joe,bob).
nephew_test_case(tim,bob).
nephew_test_case(jim,ann).
test(006, [forall(nephew_test_case(Nephew,Aunt_uncle)),nondet]) :-
nephew(Nephew,Aunt_uncle).
:- end_tests(family).
These are run with run_tests.
?- run_tests.
% PL-Unit: family ................. done
% All 17 tests passed
true.
See: Prolog Unit Tests

Why is my predicate not backtracking?

I don't understand why my predicate doesnt backtrack and find all solutions.
person(john).
person(erik).
allExceptSpider(person(Spider),T ):-
setof(person(X),person(X),S),
subtract(S,[person(Spider) ],T).
If I call this predicate with Two variables:
allExceptSpider(person(Z),Q)
Then it will only give me the answer Z = john, Q = [person(erik)]
but it won't backtrack to find Z = erik ,Q = [person(john)]
why?
TL;DR: If you use subtract/3 , your code may lose logical-purity.
person(john).
person(erik).
allExceptSpider(Spider, T) :-
setof(X, person(X), S),
subtract(S, [Spider], T).
Preserve purity! How? Use list_item_subtracted/3 like so:
allExceptSpiderNU(Spider, T) :-
setof(X, person(X), S),
list_item_subtracted(S, Spider, T).
Sample queries head-to-head:
?- allExceptSpider(Z, Q).
Q = [erik], Z = john.
?- allExceptSpiderNU(Z,Q).
Q = [ erik] , Z=john
; Q = [john ], Z=erik
; Q = [john,erik], dif(Z,erik), dif(Z,john).

Create a list in prolog from facts

I want to create a list from facts like:
table(mickel).
table(harris).
table(wolfgang).
table(yanis).
table(antti).
table(peter).
table(jeroen).
table(johan).
table(luis).
table(eric).
But i don't want to use built-in rules or predicates,
unless i define them by myself.
The result almost is like that:
?- seats(Seats).
Seats = [yanis,antti,peter,jeroen,johan,luis,eric,michel,
harris,wolfgang]
I don't know what to do,please help.
You must create your own findall predicate, this post may help:
seats(L) :- find([], L), !.
find(Acc, Loa) :- table(Y), uList(Y, Acc, AccNew), find(AccNew, Loa).
find(Acc, Acc).
uList(X, [], [X]) :- !.
uList(H, [H|_], _) :- !, fail.
uList(X, [H|T], [H|Rtn]) :- uList(X, T, Rtn).
Consult:
?- seats(L).
L = [mickel, harris, wolfgang, yanis, antti, peter, jeroen, johan, luis|...].

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.

grandfather predicate in Prolog

I have written the following program in SWI-Prolog:
male(reza).
male(aliakbar).
male(behrooz).
male(said).
male(aliasghar).
male(taghi).
male(gholamreza).
male(hadi).
female(fatema).
female(tahere).
female(olya).
female(fatema).
mother(fateme,reza).
mother(olya,hasan).
mother(x,y) :-
wife(x,z),
father(z,y).
brother(said,reza).
brother(x,y) :-
father(z,x),
father(z,y),
x\==y,
male(x).
sister(tahere,fateme).
sister(x,y) :-
father(z,x),
father(z,y),
x\==y,
female(x).
sister(olya,aliakbar).
wife(tahere,gholamreza).
father(gholamreza,hadi).
father(gholamreza, nastaran).
father(abdollah,hasan).
father(aliakbar,reza).
father(taghi,olya).
father(taghi,aliakbar).
father(taghi,aliasghar).
father(aliakbar,said).
grandfather(x,z) :-
father(x,y),
father(y,z).
grandfather(x,z) :-
father(x,y),
mother(y,z).
uncle(y,x) :-
father(z,x),
brother(z,y),
male(y).
aunt(y,x) :-
mother(z,x),
sister(z,y),
female(y).
cousin(y,x) :-
aunt(z,x),
mother(z,y),
female(y).
cousin(y,x) :-
aunt(z,x),
mother(z,y),
male(y).
When I consult "father(X,Y),father(Y,Z)." it returns the correct answer (names are in persian), i.e. it returns
X = taghi,
Y = aliakbar,
Z = reza ;
X = taghi,
Y = aliakbar,
Z = said ;
false.
But I could not find the correct answer of grandfather(X,Y). Please help me why.
Thanks.
Be careful: case is crucial in Prolog. Your rules cannot be interpreted right because you didn't use capitals for variables.

Resources