Doing exercise 10.4 on learnprolognow, could someone explain to me or help me visualize why for ?- p(X),p(Y)
we get:
X=1,Y=1; X=1,Y=2; X=2, Y=1; X=2, Y=1.
And not just
X=1, Y=1; X=1, Y=2.
I think I'm misunderstanding how the cut happens, when it's in the ruleset instead of the query - because I think I can visualize it for ?- p(X),!,p(Y).
, where it actually behaves as I thought the last one would...
Edit: From the website
% database
p(1).
p(2):-!.
p(3).
% Queries
p(X). % returns: X=1; X=2.
p(X),p(Y). % returns: X=1,Y=1; X=1, Y=1; X=2, Y=2. (?)
p(X),!,p(Y). % returns X=1, Y=1; X=1, Y=2.
To understand this problem you can imagine a tree with X
in as first level and Y
as second level (prolog uses sld resolution that can be well described with a tree). Consider this problem:
p(1).
p(2):-!.
p(3).
sol(X,Y):-
p(X),
p(Y).
I've added the predicate solve/2
to make it more clear. Run the query:
?- solve(X,Y).
First of all you have to choose the value for X
. Prolog uses depth first search from the top to the bottom, from left to right. So it evaluates p(x)
: p(1)
succeed (because is the first clause, if you write p(2)
above p(1)
, p(2)
will succeed) and so X = 1
. Then evaluates p(Y)
: p(1)
succeed and so you have the first solution:
X = Y, Y = 1.
If you click on more, then prolog does a backtrack (you can imagine this as a step above on the tree) and tries another value for p(Y)
. In this case p(2)
succeed, the predicate is true and you get:
X = 1, Y = 2.
Now, if you click on more, due to the fact there is a cut (!
) in the body of p(2)
(a general rule in prolog has the form head :- body
), prolog will not go more in depth and p(3)
is ignored. So there's no more solution to p(Y)
. So there is another backtracking and this time, for p(X)
, p(2)
succeed and X = 2
and for p(Y)
, p(1)
succeed and you get:
X = 2, Y = 1.
If you click on more, you get:
X = Y, Y = 2.
Now, due to the fact there is a cut after p(2)
, there are no more solutions available for both X
and Y
(!
cuts everything below p(2)
).
If you remove the cut you get all the possible solutions:
X = Y, Y = 1
X = 1,
Y = 2
X = 1,
Y = 3
X = 2,
Y = 1
X = Y, Y = 2
X = 2,
Y = 3
X = 3,
Y = 1
X = 3,
Y = 2
X = Y, Y = 3
Keep in mind that the order of the clauses is important. If you write
p(2).
p(1):-!.
p(3).
You get
X = Y, Y = 2
X = 2,
Y = 1
X = 1,
Y = 2
X = Y, Y = 1
You can check this behaviour using the tracer. In SWI or SWISH you can write ?-
trace, solve(X,Y).
If you have a situation like this:
p(1).
p(2).
p(3).
sol(X,Y):-
p(X),
!,
p(Y).
prolog will tests all the possible values for Y
and only one value for X
because the cut stops the exploration of the tree (ideally you have 3 branches for X
(1,2,3) and 3 for Y
(1,2,3), !
cuts 2 and 3 from X
) and you get:
X = Y, Y = 1
X = 1,
Y = 2
X = 1,
Y = 3
Sorry for the long post, hope to be clear.