Prolog query in code - prolog

How do you execute a query in the code?
For example:
person(abe,instructor).
person(bob,student).
person(cindy,student).
person(david,student).
person(abe,student).
% Like this, but this does not work
% :- person(X,Y).
After loading the program, I can run the following query: person(X,Y).
How can I run this query as part of the program itself so once the program loads, it will run the query and output:
X = abe,
Y = instructor ;
X = bob,
Y = student ;
X = cindy,
Y = student ;
X = david,
Y = student ;
X = abe,
Y = student.

You could just create a new predicate.. 2 different ways here. The first finds all person(X,Y), puts them into a list AllPeople, then writes it out.
The second is a 'failure driven loop' which does the first match, writes it out, then tells prolog to try again ie' fail', which continues until there are no more matches, and then matches the second predicate of the same name, to ensure that the predicate finally returns true.
showpeople1 :-
findall(X/Y, person(X,Y), AllPeople),
write(AllPeople).
showpeople2 :-
person(X, Y),
write(X), write(','), write(Y), nl,
fail.
showpeople2 :- true.
?- showpeople1.
[abe/instructor,bob/student,cindy/student,david/student,abe/student]
true.
?- showpeople2.
abe,instructor
bob,student
cindy,student
david,student
abe,student
true.

Related

Why does my predicate not work, when a similar predicate does?

I have the following facts:
loves(andy, julia).
loves(andrew, maria).
loves(bob, sofia).
loved(juila).
loved(maria).
loved(sofia).
and I want to have two predicates:
do_love(X, Y) :- ...
is_loved(X, Y) :- ...
which returns Y as the name of the person, and X as the fact itself. For the loved fact, I wrote:
is_loved(X, Y) :- X = loved(Y), X.
which as expected, returns:
is_loved(X,Y).
X = loved(juila),
Y = juila ;
X = loved(maria),
Y = maria ;
X = loved(sofia),
Y = sofia.
However, when I write the predicate for the loves fact in a similar way:
do_love(X, Y) :- X = loves(X, Y), X.
it returns false for the query:
do_love(X,Y).
false.
I'm new to prolog, and can't really see why this is the case. Why does the query for is_loved work, while the one for do_love doesn't?
The problem is you're trying to unify X with two different values:
X = loves(...) and
loves(X, ...)
(I truncate using ... because those parts are irrelevant to what I'm saying).
In other words, your do_love predicate is saying "X must unify with a loves predicate" and also "X must unify with the first argument in a loves predicate". With the data set you've set up, no single value fulfills both requirements.
Depending on what you're trying to do, this might be what you want:
do_love(X, Y) :- loves(X, Y).
Sidenote 1: Predicates don't "return" values like they do in other languages with functions. You don't need the , X in your predicates for them to work.
Sidenote 2: The = is a "unify" operator, rather than an "assignment" like other languages. See this page for more info.

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

Nephew of my own father in prolog

i'm programming a family in prolog and i'm having trouble with the nephew implementation. When I ask if erick is the nephew of Alberto it returns true, when it should return false because Alberto is the father of erick, however, it does works for all the other cases that should be true. If someone could help me I would be very grateful.
My code:
man(beto).
man(fransisco).
man(alberto).
man(jaime).
man(manolo).
man(nolo).
man(lito).
man(manuel).
man(erick).
man(jesu).
man(jesus).
woman(emi).
woman(harumi).
woman(haru).
woman(yuneisi).
woman(yasmeli).
woman(mioara).
woman(elia).
woman(iza).
woman(alice).
woman(ofelia).
woman(arlet).
parent(manuel, alberto).
parent(ofelia, alberto).
parent(manuel, jaime).
parent(ofelia, jaime).
parent(manuel, manolo).
parent(ofelia, manolo).
parent(alberto, erick).
parent(alberto, beto).
parent(alberto, fransisco).
parent(emi, erick).
parent(emi, beto).
parent(manolo, nolo).
parent(manolo, arlet).
parent(nolo, lito).
parent(iza, lito).
parent(mioara, yuneisi).
parent(mioara, yasmeli).
parent(jaime, yuneisi).
parent(jaime, yasmeli).
parent(jesus_padre, jesu)
parent(jesus_padre, alice).
parent(jesus_padre, haru).
parent(harumi, haru).
parent(harumi, jesu).
parent(harumi, alice).
father(X,Y) :- parent(X,Y), man(X).
mother(X,Y) :- parent(X,Y), woman(X).
brother(X,Y) :- man(X), parent(F, X), parent(F, Y).
sister(X,Y) :- woman(X), parent(P, X), parent(P, Y).
grandpa(X,Y) :- father(F,Y), father(X,F), man(X).
grandma(X,Y) :- father(F,Y), mother(X,F), woman(X).
son(X,Y) :- father(Y,X), man(X).
nephew(X,Y) :- father(F,X), brother(F,Y).
Besides the missing dot after parent(jesus_padre, jesu) as pointed out by #LuaiGhunim there are a few other issues with your predicates. Your definition of brother/2 is too general. Nobody is his own brother but if you query your predicate you find several such instances:
?- brother(X,X).
X = beto ;
X = beto ;
X = fransisco ;
X = alberto ;
X = alberto ;
X = jaime ;
X = jaime ;
X = manolo ;
X = manolo ;
X = nolo ;
X = lito ;
X = lito ;
X = erick ;
X = erick ;
X = jesu ;
X = jesu ;
false.
You can easily remedy this by adding a goal dif/2:
brother(X,Y) :-
dif(X,Y),
man(X),
parent(F, X),
parent(F, Y).
Now the query above fails as it should:
?- brother(X,X).
false.
You'll still get a lot of pairs twice:
?- brother(X,Y).
X = beto, % <- 1st occurrence
Y = erick ; % <- 1st occurrence
X = beto,
Y = fransisco ;
X = beto, % <- 2nd occurrence
Y = erick ; % <- 2nd occurrence
.
.
.
The reason for that is that you can derive it via the mother or the father. In the above example (beto and erick) you'll get there via emi or alberto. These solutions might be redundant but they are correct. The same goes for your predicate sister/2:
?- sister(X,X).
X = haru ;
X = haru ;
X = yuneisi ;
X = yuneisi ;
X = yasmeli ;
X = yasmeli ;
X = alice ;
X = alice ;
X = arlet.
The remedy is the same as above:
sister(X,Y) :-
dif(X,Y),
woman(X),
parent(P, X),
parent(P, Y).
?- sister(X,X).
false.
?- sister(X,Y).
X = haru,
Y = jesu ;
X = haru,
Y = alice ;
X = haru,
Y = jesu ;
.
.
.
Your definition of grandma/2 and grandpa/2 on the other hand is too specific. To see this let's add the following facts to your code:
man(m1).
man(m2).
woman(w1).
woman(w2).
woman(w3).
parent(m1,w1).
parent(w1,w2).
parent(w2,w3).
Then the following queries should succeed but they fail instead:
?- grandpa(m1,w2).
false.
?- grandma(w1,w3).
false.
The reason for this is that the intermediate parent in your definition of grandpa/2 and grandma/2 is a father/2 where it should be a parent/2. Additionally the last goals (man(X) and woman(X)) are redundant since they are already covered by father/2 and mother/2 respectively. Instead, you could define the two predicates like so:
grandpa(X,Y) :-
parent(F,Y),
father(X,F).
grandma(X,Y) :-
parent(F,Y),
mother(X,F).
Now the above queries yield the desired result:
?- grandpa(m1,w2).
true.
?- grandma(w1,w3).
true.
Finally, a nephew according to the Cambridge Dictionary is a son of your sister or brother, or a son of the sister or brother of your husband or wife. Since you haven't got predicates for husbands and wives I'll stick with the a son of your sister or brother part. If you add facts for husbands and wives, you can add additional rules to cover the other part of the definition. You can write the first part of the definition in Prolog like so:
nephew(X,Y) :-
man(X),
dif(F,Y),
parent(P,F),
parent(P,Y),
parent(F,X).
If you query this predicate there's no erick/alberto solution any more:
?- nephew(erick,X).
X = jaime ;
X = manolo ;
X = jaime ;
X = manolo ;
false.
Prolog it's all about relations. Joins plays a fundamental role. So, often you can think in term of 'yields', or functions over the DB, and design/control the data access plan by means of joins (clauses, i.e. logical formulae) producing records - like SQL does. The procedural execution over the retrieved data is expressed in (almost) the same language: joins, giving us a taste of declarative programming. Anyway, here are the clauses provided by #tas in standard Prolog:
brother(X,Y) :-
man(X),
parent(F, X),
parent(F, Y),
X\=Y.
sister(X,Y) :-
woman(X),
parent(P, X),
parent(P, Y),
X\=Y.

Trying to check lines are between 2 points that exist, Prolog

I am trying to check whether lines are actually between 2 points that exist in the rule set. For example in the code below,
point(a).
point(z).
line(l,k).
line(k,l).
line(k,a).
line(a,z).
line(a,z). is a real line because a and z are both points in the rule set but line(l,k). isn't a real line because l and k aren't real points in the rule set.
I am new to Prolog and would just like some pointers for how to do this.
You could write:
real_line(X,Y):-line(X,Y),point(X),point(Y).
The , in Prolog means logical "and" so the above predicate real_line/2 succeeds when for X,Y holds: line(X,Y) and X is a point and Y is a point.
Some examples:
?- real_line(a,z).
true.
?- real_line(a,k).
false.
?- real_line(l,k).
false.
?- real_line(X,Y).
X = a,
Y = z.
?- real_line(X,z).
X = a.
?- real_line(a,Y).
Y = z.
UPDATE
Based on your comments to find all incorrect lines you could use:
findall(line(X,Y),(line(X,Y), \+ real_line(X,Y)),L).
Example:
?- findall(line(X,Y),(line(X,Y), \+ real_line(X,Y)),L).
L = [line(l, k), line(k, l), line(k, a)].
OR with a fail-driven loop:
write_incorrect_lines:-
line(X,Y),
\+real_line(X,Y),
write(line(X,Y)),
nl,
fail;
true.
Example:
?- write_incorrect_lines.
line(l,k)
line(k,l)
line(k,a)
true.

How to return two values from a basic predicate(?) in Prolog?

I just started going over Prolog about an hour ago and have already stumbled into a slight problem I am unsure about. I am writing a predicate (or function?) that takes a list and returns the min and max values. Right now, I am just looking at one of the special cases when the list has 1 item. For example, if you query minmax([5], X, Y). I want the predicate to return X=5 Y=5. I have this code:
minmax([X], X, X).
but it is returning X = Y, Y = 5. I know it is a true statement and trivial, but is there a way I can return X=5,Y=5 ???
It is returning what you think it is. X is 5 as is Y. The values are unified and so the interpreter shows the message X=Y, Y=5. You need to get out the Prolog textbook and read up on unification of terms.
You could just as easily say
foo(A,B) :- A = 5 , B is (A+A)/2 .
and query it:
?- foo(X,Y).
and get the same result. In the Prolog universe, there is only ever a single instance of the integer 5.
X=Y, Y=5 means that X and Y are now both equal to 5. It's just a different way of saying that; you really shouldn't care. If you print both values, you'll just get 5:
?- [user].
|: print_stuff :-
|: X = Y,
|: Y = 5,
|: write('X = '), writeln(X),
|: write('Y = '), writeln(Y).
|: % user://1 compiled 0.02 sec, 2 clauses
true.
?- print_stuff.
X = 5
Y = 5
true.

Resources