Prolog, about how to form better clauses - prolog

I have following clauses:
num_parent(adam, X) :- !, X = 0.
num_parent(eve, X) :- !, X = 0.
num_parent(X, 2).
When I typed the query:
num_parent(eve,X).
It only returns:
X = 0.
which is what I want.
But when I typed this query:
num_parent(X,0).
it only returns:
X = adam.
So how can I modify the clauses to make it return:
X = adam;
X = eve.
Thanks

First, try to formulate what you want in plain English. You probably want to say:
Everyone has two parents except Adam and Eve who have none.
What about Lilith? Never mind, let's stick to your reading.
num_parent(Person, 2) :-
dif(Person, adam),
dif(Person, eve).
num_parent(adam, 0).
num_parent(eve, 0).
As you can see, it is a bit cumbersome to define this: You have to mention each exceptional person twice. Easy to make an error.
With if_/3 available in library(reif)
for
SICStus and
SWI
you can write more succinctly:
num_parent(Person, Num) :-
if_( ( Person = adam ; Person = eve ), Num = 0, Num = 2 ).
And now some uses:
?- num_parent(eve, Num).
Num = 0.
?- num_parent(X, 0).
X = adam
; X = eve
; false.
?- num_parent(X, 2).
dif(X, eve), dif(X, adam).
?- num_parent(lilith, 2).
true.

The programs returns only X = adam because you inserted the cut !. The cut is used when you have found the right rules and you don't need to do further evaluations, but it cuts all the other solutions.
In your case
num_parent(adam, X) :- !, X = 0.
num_parent(eve, X) :- !, X = 0.
num_parent(_, 2). %replaced num_parent(X, 2) with num_parent(_, 2) to avoid singleton variable
num_parent(X, 0) returns only X = adam.
If you write
num_parent(adam, X) :- X = 0.
num_parent(eve, X) :- !, X = 0.
num_parent(_, 2).
the solution will be X = adam and X = eve, and in this case:
num_parent(adam, X) :- X = 0.
num_parent(eve, X) :- X = 0.
num_parent(_, 2).
the solution will be X = adam, X = eve and false because the query num_parent(X, 0) doesn't unify with num_parent(_, 2).
You can better see this behavior using the tracer.

Related

Why do both predicates get evaluated?

I have this predicate with two clauses:
abs(X, Y) :- X < 0, Y is -X.
abs(X, X) :- X >= 0.
and I submit this to the interpreter:
?- abs(-5,W).
W = 5 ;
false.
?-
Why does it evaluate the second clause and return false? Is there a way around that?
You wrote two clauses that are disjoint on the 1st argument(X) and were surprised that Prolog backtracked into the 2nd one even though the first one was satisfied.
abs(X, Y) :- X < 0, Y is -X.
abs(X, X) :- X >= 0.
When the 1st clause was satisfied, the Prolog engine only knew that there was a 2nd clause that hadn't been evaluated; when you typed ";", it tried the 2nd clause, which failed. To see why, consider a slightly different (and not as good) version of your code:
abs2(X, Y) :- X =< 0, Y is - X.
abs2(X, Y) :- X >= 0, Y = X.
?- abs2(0, Y).
Y = 0 ;
Y = 0 ;
In this situation, even though the 1st clause succeeds, the 2nd clause can also succeed.
So, how to avoid this? It depends on what you want to accomplish. If you want to get all the answers, do something like this:
?- setof(W, abs(-5, W), Ws).
Ws = [5].
To print them all:
?- forall(abs(-5, W), format('W = ~q~n', [W])).
W = 5
If you want to tell the Prolog engine that your predicate is deterministic, you can use an if-then-else:
abs(X, Y) :-
( X < 0
-> Y is -X
; Y = X
).
This can also be written with a cut("!"), but it's often easier to understand with if-then-else.
And, if you're using the latest version of SWI-Prolog, you can use the "=>" notation:
abs(X, Y), X < 0 => Y is -X.
abs(X, Y) => true.

Boolean unification in Prolog?

I am struggling alreay for a long time with the
following problem. I want to make the usual unification
of Prolog more smart.
Basically I want that certain variables understand that
for example 0 = ~1 and 1 = ~0. This doesn't work normally:
?- op(300, fy, ~).
true.
?- X = ~Y, Y = 0.
X = ~0,
Y = 0.
I know that that CLP(B) can do it:
Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.7)
:- use_module(library(clpb)).
true.
?- sat(X=:= ~Y), Y = 0.
X = 1,
Y = 0.
But I require something more lightweight than loading a full CLP(B) library. Any ideas?
It seems that SWI-Prologs when/2 does the job. I am using
the Quine algorithm from here to partially evaluate a boolean expression.
I can then define a Boolean let/2 predicate:
let(X, Y) :-
eval(Y, H),
term_variables(H, L),
( L== [] -> X = H;
cond(L, R),
when(R, let(X, H))).
cond([X], nonvar(X)) :- !.
cond([X,Y|Z], (nonvar(X);T)) :-
cond([Y|Z], T).
The above predicate will reevaluate the expression assigned
to the variable X when ever some variable inside the expression
changes. The expression is associate with the variable X through when/2. Since we see when/2 in the top-level, we see the associated expression:
?- let(X, ~Y).
when(nonvar(Y), let(X, ~Y))
?- let(X, Y+Z).
when((nonvar(Y); nonvar(Z)), let(X, Y+Z))
And we can also do our use case and even more:
?- let(X, ~Y), Y = 0.
X = 1,
Y = 0.
?- let(X, Y+Z), Y = 0.
Y = 0,
when(nonvar(Z), let(X, Z))
?- let(X, Y+Z), Y = 0, Z = 1.
X = 1,
Y = 0,
Z = 1

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.

Why is the following Prolog program only returning one solution?

contains(X, L) :- [X|_] = L.
contains(X, L) :- [Y|Z] = L, Y \= X, contains(X, Z).
f(R, L1, Res) :-
(R,T) = X,
contains(X, L1),
Res = T.
?- f(1, [(1,2), (1,3)], R). gives only one value of R i.e. 2, but I expect it to return 2 values of R 2 and 3.
Answer to a similar prolog question on stackoverflow.com recommends to use SPACEor ; instead of ENTER, but I get false if I press ; or SPACE after I get the first answer.
What is going wrong?
Your contains/2 is defined as:
contains(X, L) :-
[X|_] = L.
contains(X, L) :-
[Y|Z] = L,
Y \= X,
contains(X, Z).
Your Y \= X (here in boldface) however prevents the contains/2 to recurse on the tail Z once it has found an X that unifies with the head of the list. Indeed, in case Y = X, then Y \= X is false (since Y \= X is short for \+ X = Y). If Y \= X fails, we can not call contains(X, Z), and therefore it can not check of other members of the list can be emitted.
So we can remove the statement and write:
contains(X, L) :-
[X|_] = L.
contains(X, L) :-
[Y|Z] = L,
contains(X, Z).
and now contains/2 will work like member/2 works.
The code is however not very elegantly: you do unification in the body that can be done in the head. Furthermore we now have a variable L that is not used in the first clause, and a variable Y in the second clause that is not used. We can rewrite it to:
contains(X, [X|_]).
contains(X, [_|T]) :-
contains(X, T).
and that's it. Now your f/3 will work, although again it is not very elegant. We can rewrite this as well into:
f(R, L, T) :-
contains((R,T), L).
and now our f/3 predicate works in different directions:
?- f(1, [(1,2), (1,3)], R).
R = 2 ;
R = 3 ;
false.
?- f(X, [(1,2), (1,3)], 2).
X = 1 ;
false.
?- f(X, [(1,2), (1,3)], 3).
X = 1 ;
false.
?- f(X, L, 3).
L = [ (X, 3)|_G1262] ;
L = [_G1261, (X, 3)|_G1265] ;
L = [_G1261, _G1264, (X, 3)|_G1268] ;
L = [_G1261, _G1264, _G1267, (X, 3)|_G1271] .
?- f(1, L, 3).
L = [ (1, 3)|_G1250] ;
L = [_G1249, (1, 3)|_G1253] ;
L = [_G1249, _G1252, (1, 3)|_G1256] .

Predicate in prolog which is true if M and N differ more than X

First of all I am completely new to prolog and I am trying to write a predicate length(M,X,N) which is true, if M differs from N more than X.
I wrote the following testcase which is true if M(=dec.5) and N(=dec.2) differ more than X(=dec.2). And it is true in this case because 5 and 2 have a difference of 3 which is more than 2:
?- length(s(s(s(s(s(0))))), s(s(0)), s(s(0))).
true .
I know that prolog works recursively so I am wondering if I can construct such a predicate with conditions (for example <,>) like in languages like C, or if there is another way to do this in prolog. Sorry for this simple question but I just started with prolog.
You could construct predicates for greater or less. For example:
greater_than(s(_), 0).
greater_than(s(X), s(Y)) :-
greater_than(X, Y).
And similarly:
less_than(0, s(_)).
less_than(s(X), s(Y)) :-
less_than(X, Y).
If you want to find the absolute difference, you could do something like this:
abs_diff(0, 0, 0).
abs_diff(s(X), 0, s(X)).
abs_diff(0, s(X), s(X)).
abs_diff(s(X), s(Y), D) :-
abs_diff(X, Y, D).
Those concepts should help kick start some ideas for how to solve the rest of the problem.
This answer follows up on #lurker's fine answer and improves the determinism of the auxiliary predicate abs_diff/3 by utilizing
first argument clause indexing.
Introducing x_y_dist/3:
x_y_dist(0, Y, Y).
x_y_dist(s(X), Y, Z) :-
y_sx_dist(Y, X, Z).
y_sx_dist(0, X, s(X)).
y_sx_dist(s(Y), X, Z) :-
x_y_dist(X, Y, Z).
Sample query:
?- x_y_dist(X, Y, s(s(0))). % |X-Y| = 2
( X = 0 , Y = s(s(0)) % |0-2| = 2
; X = s(s(0)) , Y = 0 % |2-0| = 2
; X = s(0) , Y = s(s(s(0))) % |1-3| = 2
; X = s(s(s(0))) , Y = s(0) % |3-1| = 2
; X = s(s(0)) , Y = s(s(s(s(0)))) % |2-4| = 2
; X = s(s(s(s(0)))) , Y = s(s(0)) % |4-2| = 2
; X = s(s(s(0))) , Y = s(s(s(s(s(0))))) % |3-5| = 2
; X = s(s(s(s(s(0))))), Y = s(s(s(0))) % |5-3| = 2
; X = s(s(s(s(0)))) , Y = s(s(s(s(s(s(0)))))) % |4-6| = 2
; .........
)
Try this:
?- length(s(s(s(s(s(0))))), s(s(0)), s(s(0))).
length(s(_),0,0).
length(s(M),s(X),s(N)) :- length(M,X,N).
Do keep in mind that Prolog's predicates do not return values - so they don't return true or false. They either succeed or they don't. The interpreter is just telling you if your program succeeds or not.

Resources