Given a set of facts that represent parent-child relationships via the predicate parent/2, what are the differences when defining the relation "progenitor"(ancestor) with the predicates pred1/2 and pred2/2 as shown below?
pred1(X,Z) :- parent(X,Z).
pred1(X,Z) :- parent(X,Y), pred1(Y,Z).
pred2(X,Z) :- parent(X,Z).
pred2(X,Z) :- parent(Y,Z), pred2(X,Y).
The major difference are the termination properties of both, provided there are some cycles in the relation. To understand this, I will use a failure-slice which cuts down the program to its essence w.r.t. termination.
pred1(X,Z) :- false, parent(X,Z). pred1(X,Z) :- parent(X,Y), pred1(Y,Z). % Z has no influencepred2(X,Z) :- false, parent(X,Z). pred2(X,Z) :- parent(Y,Z), pred2(X,Y). % X has no influence
For pred1/2
, the second argument has no influence on termination at all, whereas in pred2/2
, the first argument has no influence. To see this, try the original definitions with the fact:
parent(a,a). ?- pred1(b, _), false. false. % terminates ?- pred2(b, _), false. loops. ?- pred1(_, b), false. loops. ?- pred2(_, b), false. false. % terminates
See closure/3
for a general approach to avoid such loops.
For completeness, here is another variation of transitive closure which has some conceptual advantages:
pred3(X,Z) :- parent(X,Z).
pred3(X,Z) :- pred3(X,Y), pred3(Y,Z).
Alas, its termination properties are worst. In fact, it never terminates, as is testified by the following fragment:
pred3(X,Z) :- false, parent(X,Z). pred3(X,Z) :- pred3(X,Y), false,pred3(Y,Z).
In this fragment, the first argument is only passed on. So, no matter, what the arguments are, the program will always loop!
?- pred3(b,b), false. loops.