8.4 Control

+P , +Q ISO
P and Q.
+P ; +Q ISO
P or Q.
! ISO
See Cut.
\+ +P ISO

Fails if the goal P has a solution, and succeeds otherwise. This is not real negation (“P is false”), but a kind of pseudo-negation meaning “P is not provable”. It is defined as if by

          \+(P) :- P, !, fail.
          \+(_).
     

In sicstus execution mode no cuts are allowed in P. In iso execution mode cuts are allowed in P and their scope is the goal P.

Remember that with prefix operators such as this one it is necessary to be careful about spaces if the argument starts with a `('. For example:

          | ?- \+ (P,Q).
     

is this operator applied to the conjunction of P and Q, but

          | ?- \+(P,Q).
     

would require a predicate \+ /2 for its solution. The prefix operator can however be written as a functor of one argument; thus

          | ?- \+((P,Q)).
     

is also correct.

+P -> +Q ; +R ISO
Analogous to
          if P then Q else R
     

and defined as if by

          (P -> Q; R) :- P, !, Q.
          (P -> Q; R) :- R.
     

except the scope of any cut in Q or R extends beyond the if-then-else construct. In sicstus execution mode no cuts are allowed in P. In iso execution mode cuts are allowed in P and their scope is the goal P.

Note that this form of if-then-else only explores the first solution to the goal P.

Note also that the `;' is not read as a disjunction operator in this case; instead, it is part of the if-then-else construction.

The precedence of `->' is less than that of `;' (see Operators), so the expression is read as

          ;(->(P,Q),R)
     

+P -> +Q ISO
When occurring as a goal, this construction is read as equivalent to
          (P -> Q; fail)
     

if(+P,+Q,+R)
Analogous to
          if P then Q else R
     

but differs from P -> Q ; R in that if(P, Q, R) explores all solutions to the goal P. There is a small time penalty for this—if P is known to have only one solution of interest, the form P -> Q ; R should be preferred.

In sicstus execution mode no cuts are allowed in P. In iso execution mode cuts are allowed in P and their scope is the goal P.

once(+P) ISO
Finds the first solution, if any, of goal P. Fails if no solutions are found. Will not explore further solutions on backtracking. Equivalent to
          (P -> true; fail)
     

otherwise
true ISO
These always succeed. Use of otherwise/0 is discouraged, because it is not as portable as true/0, and because the former may suggest a completely different semantics than the latter.
false
fail ISO
These always fail. Use of false/0 is discouraged, because it is not as portable as fail/0, and because the latter has a more procedural flavor to it.
repeat ISO
Generates an infinite sequence of backtracking choices. In sensible code, repeat/0 is hardly ever used except in repeat loops. A repeat loop has the structure
          Head :-
                  ...
                  save_state(OldState),
                  repeat,
                    generate(Datum),
                    action(Datum),
                    test(Datum),
                  !,
                  restore_state(OldState),
                  ...
     

The purpose is to repeatedly perform some action on elements that are somehow generated, e.g. by reading them from a stream, until some test becomes true. Usually, generate, action, and test are all determinate. Repeat loops cannot contribute to the logic of the program. They are only meaningful if the action involves side-effects.

The only reason for using repeat loops instead of a more natural tail-recursive formulation is efficiency: when the test fails back, the Prolog engine immediately reclaims any working storage consumed since the call to repeat/0.

call(:Term) ISO
incore(:Term) obsolescent
:Term
If Term is instantiated to a term that would be acceptable as the body of a clause, then the goal call(Term) is executed exactly as if that term appeared textually in its place, except that any cut (!) occurring in Term only cuts alternatives in the execution of Term. Use of incore/1 is not recommended.

If Term is not instantiated as described above, an exception is raised.

call_cleanup(:Goal,:Cleanup)
This construction can be used to ensure that Cleanup is executed as soon as Goal has completed execution, no matter how it finishes. In more detail:

When call_cleanup/2 with a continuation C is called or backtracked into, first Goal is called or backtracked into. Then there are four possibilities:

  1. Goal succeeds determinately, possibly leaving some blocked subgoals. Cleanup is executed with continuation C.
  2. Goal succeeds with some alternatives outstanding. Execution proceeds to C. If a cut that removes the outstanding alternatives is encountered, Cleanup is executed with continuation to proceed after the cut. Also, if an exception E that will be caught by an ancestor of the call_cleanup/2 Goal is raised, Cleanup is executed with continuation raise_exception(E).
  3. Goal fails. Cleanup is executed with continuation fail.
  4. Goal raises an exception E. Cleanup is executed with continuation raise_exception(E).

In a typical use of call_cleanup/2, Cleanup succeeds determinately after performing some side-effect; otherwise, unexpected behavior may result.

Note that the Prolog top-level operates as a read-execute-fail loop, which backtracks into or cuts the query when the user types ; or <RET> respectively. Also, the predicates halt/0 and abort/0 are implemented in terms of exceptions. All of these circumstances can trigger the execution of Cleanup.