JumbleGee
JumbleGee

Reputation: 85

How come this Prolog rule doesn't go into a infinity loop?

I have following facts and rules:

one(s).
one(t).
two(X,Y) :- one(X), one(Y), three(X), \+three(Y), \+two(Y,X).
three(s).

For the query two(Y,X). I get this result:

?- two(Y,X).
Y = s,
X = t ;
false.

I don't understand why the results are Y=s and X=t. Why does Prolog don't go infinitely many times into \+two(Y,X)? Does Prolog remember which predicates have already been processed?

Upvotes: 2

Views: 69

Answers (2)

Will Ness
Will Ness

Reputation: 71119

You have the following predicates defined:

one(s).
one(t).
two(X,Y) :- one(X), one(Y), three(X), \+three(Y), \+two(Y,X).
three(s).

The predicate two(X,Y) is equivalent to

two(X,Y) :- (X=s ; X=t), (Y=s ; Y=t), (X=s), \+(Y=s), \+two(Y,X).
=
two(X,Y) :- (X=s, (Y=s ; Y=t), X=s ; X=t, (Y=s ; Y=t), X=s), \+(Y=s), \+two(Y,X).
=
two(X,Y) :- (X=s, (Y=s ; Y=t), s=s ; X=t, (Y=s ; Y=t), t=s), \+(Y=s), \+two(Y,X).
=
two(X,Y) :- (X=s, (Y=s ; Y=t) ; false), \+(Y=s), \+two(Y,X).
=
two(X,Y) :- ((X=s, Y=s ; false), \+(Y=s) ; (X=s, Y=t ; false), \+(Y=s)), \+two(Y,X).
=
two(X,Y) :- ((X=s, Y=s ; false), \+(s=s) ; (X=s, Y=t ; false), \+(t=s)), \+two(Y,X).
=
two(X,Y) :- (X=s, Y=t ; false), true, \+two(Y,X).
=
two(X,Y) :- (X=s, Y=t, \+two(Y,X) ; false).
=
two(s,t) :- (true, \+two(t,s) ; false).
=
two(s,t) :- (true ; false).

and that's what you're getting.

Upvotes: 1

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477684

This succeeds because Prolog uses negation as finite failure.

If we evaluate the Prolog predicate, we see that:

[trace]  ?- two(X, Y).
   Call: (8) two(_660, _662) ? creep
   Call: (9) one(_660) ? creep
   Exit: (9) one(s) ? creep
   Call: (9) one(_662) ? creep
   Exit: (9) one(s) ? creep
   Call: (9) three(s) ? creep
   Exit: (9) three(s) ? creep
   Call: (9) three(s) ? creep
   Exit: (9) three(s) ? creep
   Redo: (9) one(_662) ? creep
   Exit: (9) one(t) ? creep
   Call: (9) three(s) ? creep
   Exit: (9) three(s) ? creep
   Call: (9) three(t) ? creep
   Fail: (9) three(t) ? creep
   Redo: (8) two(s, t) ? creep
   Call: (9) two(t, s) ? creep
   Call: (10) one(t) ? creep
   Exit: (10) one(t) ? creep
   Call: (10) one(s) ? creep
   Exit: (10) one(s) ? creep
   Call: (10) three(t) ? creep
   Fail: (10) three(t) ? creep
   Fail: (9) two(t, s) ? creep
   Redo: (8) two(s, t) ? creep
   Exit: (8) two(s, t) ? creep
X = s,
Y = t .

So in a first "path" that fails X and Y are both set to s:

two(X,Y) :-
    one(X),     %% X = s
    one(Y),     %% Y = s
    three(X),   %% X = s
    \+three(Y), %% Y = s, fail
    \+two(Y,X).

But then we backtrack over the one(Y) call, and we obtain:

two(X,Y) :-
    one(X),     %% X = s
    one(Y),     %% Y = t
    three(X),   %% X = s
    \+three(Y), %% Y = t
    \+two(Y,X)  %% call two(t, s).

Now \+ p(X, Y) is considered true, given p(X, Y) can not be satisfied, and gets stuck in an infinite loop. We thus call two(t, s), and this fails, since:

two(t,s) :-
    one(t),     %% succeeds
    one(s),     %% succeeds
    three(t),   %% fails
    \+three(s), %% 
    \+two(s,t)  %% 

So three(t) fails, and since there are no backtracking opportunities here, two(t, s) thus ends. So that means that two(t, s) has finite failure, hence \+ two(t, s) succeeds, and thus two(X, Y) succeeds with X = s, Y = t.

Upvotes: 1

Related Questions