Reputation: 23
I am just starting to learn Prolog and I played around with it. Now I got to a point where I´m stuck. The program i wrote gets into an infinite loop when I ask for
?- q(b).
and I don´t understand why it does that. It would be nice if someone could explain it to me.
p(a).
p(b).
q(Y) :- r(X), r(Y).
r(X) :- r(f(X)).
r(a) :- p(c).
r(a) :- p(a).
r(b) :- p(b).
Upvotes: 2
Views: 207
Reputation: 10142
Another way to identify reasons for non-termination is to reduce the number of inferences your program will execute by adding goals false
into your program:
q(Y) :- r(X), false, r(Y).
r(X) :- r(f(X)), false.
r(a) :- false, p(c).
r(a) :- false, p(a).
r(b) :- false, p(b).
?- q(Y).
loops.
Since this program is still looping, you will need to modify something in the visible part. Note how many things have been removed entirely! No matter how p/1
is defined, this problem will persist.
If you look at q/1
closely, you see one of the problems:
q(Y) :- r(X), false,r(Y).
The variable Y
is not used in the visible part at all. The X
appears just once. Thus, r(X)
will be the most general query possible and thus it will have the worst termination property possible (that depends on the definition of r/1
, indeed). In any case, the argument of q/1
has no influence on termination!
There is another property to conclude: The order of clauses does not have any influence on the termination property! You can see this easily: No matter where the clauses that have been removed entirely with false
appear, they can be removed.
For more, see failure-slice.
Upvotes: 1
Reputation: 2662
As said in the comment, the loop is caused by r/1
. To show why, yust type ?- trace, q(b).
Look at the trace (ignore by now the singleton warning):
Call:q(b)
Call:r(_4244)
Call:r(f(_4162))
Call:r(f(f(_4162)))
Call:r(f(f(f(_4162))))
Call:r(f(f(f(f(_4162)))))
Call:r(f(f(f(f(f(_4162))))))
Call:r(f(f(f(f(f(f(_4162)))))))
Call:r(f(f(f(f(f(f(f(_4162))))))))
Now you can see that it try to derives r/1
entering a loop. You can see also this question to have a more in depth explaination.
Notice that in prolog, the order of the clauses matters. Just try to put the line r(X) :- r(f(X)).
to the bottom of your program. Now try ?- q(b).
On the first answer you get true
because prolog unifies X
with a
and Y
with b
before entering in a loop.
Upvotes: 4