Equivalence of disjunction operator and definition with several rules

Wouldn't that mean that ;/2 behaves exactly as if we wrote our own helper predicate consisting of two rules?

No. Term-to-body conversion makes the difference.

But first, its (;)/2 which is defined in both 7.8.6 (disjunction) and 7.8.8 (if-then-else) — as the very first sentence in 7.8.6 suggests. For the round brackets around ; see the note in 7.1.6.6.

So the first question is how it is possible to decide which subclause applies in case you see ( G_0 ; H_0 ) in your program. This does not depend on the instantiation present when calling (;)/2 but rather it depends on the instantiation during term-to-body conversion (7.6.2).

?- G_0 = ( true -> X = si ), ( G_0 ; X = nisi ).
   G_0 =  (true->si=si),
   X = si
;  G_0 =  (true->nisi=si),
   X = nisi.

?- G_0 = ( true -> X = si ), call( ( G_0 ; X = nisi ) ).
   G_0 =  (true->si=si),
   X = si.

In the first query term-to-body conversion replaces within the disjunction G_0 by call(G_0) and thus

( call( ( true -> X = si ) ) ; X = nisi ) )

will be executed.

In the second query there are two term-to-body conversions once for the entire query and once for the explicit call/1, but both leave everything as is, and thus

call( ( true -> X = si ; X = nisi ) )

will be executed and the else case is left out.

Further differences due to term-to-body conversion are for cuts and errors due to malformed bodies.


As far as I know, defining

p(X) :- G1 ; G2 .

is the same as defining

p(X) :- G1 .
p(X) :- G2 .

And yes, you're mixing this ; with the somewhat related but completely different _ -> _ ; _.