prologiso-prolog

Equivalence of disjunction operator and definition with several rules


I just stumbled over the definition of ;/2 in the SWI Prolog Manual which states:

The `or' predicate is defined as:

Goal1 ; _Goal2 :- Goal1.
_Goal1 ; Goal2 :- Goal2.

Wouldn't that mean that ;/2 behaves exactly as if we wrote our own helper predicate consisting of two rules? I had memorized that ;/2 was an impure construct (but it's possible I'm mixing this up with if-then-else) but this definition is pure (although meta-logical).

The semantics of ;/2 are defined in the ISO standard in paragraph 7.8.6 but this is done in terms of manipulation of the current state, choice points etc.

Is the definition in the SWI manual equivalent to the ISO definition? If no, do you know an example where they differ?


Solution

  • 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.