Did you know ... | Search Documentation: |
Control Predicates |
The predicates of this section implement control structures. Normally the constructs in this section, except for repeat/0, are translated by the compiler. Please note that complex goals passed as arguments to meta-predicates such as findall/3 below cause the goal to be compiled to a temporary location before execution. It is faster to define a sub-predicate (i.e., one_character_atoms/1 in the example below) and make a call to this simple predicate. See also the Prolog flag compile_meta_arguments.
one_character_atoms(As) :- findall(A, (current_atom(A), atom_length(A, 1)), As).
t0 :- (a, !, b). | % prunes a/0 and t0/0 |
t1 :- (a, !, fail ; b). | % prunes a/0 and t1/0 |
t2 :- (a -> b, ! ; c). | % prunes b/0 and t2/0 |
t3 :- (a, !, b -> c ; d). | % prunes a/0 |
t4 :- call((a, !, fail ; b)). | % prunes a/0 |
t5 :- | % prunes a/0 |
?- (between(1,2,X) ; X = a). X = 1 ; X = 2 ; X = a.
It is strongly advised to always use parenthesis around
disjunctions. Conjunctions inside a disjunction should not use
parenthesis. Traditionally the
is placed at
the start of the line rather than at the end because a ;
at the end of a line is easily overlooked. Below is an example of the
preferred style used in SWI-Prolog.74Some
users prefer a newline after the ;
.
;
p :- a, ( b, c ; d ).
Although ;/2 is a control structure that is normally handled by the compiler, SWI-Prolog implements ;/2 as a true predicate to support call/2 and friends as well as to allow for querying predicate properties, for example to support code analysis.
If -> Then; _Else :- If, !, Then. If -> _Then; Else :- !, Else. If -> Then :- If, !, Then.
Please note that (If ->
Then) acts as (If ->
Then ;
fail), making the construct fail if the condition fails.
This unusual semantics is part of the ISO and all de-facto Prolog
standards.
Please note that (if->
then;else) is read as ((if->
then);else)
and that the combined semantics of this syntactic construct as
defined above is different from the simple nesting of the two
individual constructs, i.e., the semantics of
->/2 changes
when embedded in ;/2. See
also
once/1.
As with ;/2, this construct is always nested in parenthesis. Here is an example of the preferred layout for SWI-Prolog.
p :- a, ( b, c -> d, e ; f -> g ; h ).
call(Condition)
,
Action).75Note that the Condition
is wrapped in call/1,
limiting the scope of the cut (!/0
If
Condition does not succeed, the semantics is that of (\+
Condition, Else). In other words, if Condition
succeeds at least once, simply behave as the conjunction of
call(Condition)
and Action, otherwise execute Else.
The construct is known under the name if/3 in some other Prolog
implementations.
The construct A *->
B, i.e.,
without an Else branch, the semantics is the same as (call(A)
, B).
This construct is rarely used. An example use case is the implementation of optional in sparql. The optional construct should preserve all solutions if the argument succeeds as least once but still succeed otherwise. This is implemented as below.
optional(Goal) :- ( Goal *-> true ; true ).
Now calling e.g., optional(member(X, [a,b]))
has the
solutions
X=a and X=b, while optional(member(X,[]))
succeeds without binding X.
+
refers to provable and the backslash (\
)
is normally used to indicate negation in Prolog). In contrast to the ISO
standard, but compatible with several other Prolog systems, SWI-Prolog
implements
\+/1 as a control
structure. This implies that its argument is compiled as part of
the enclosing clause and possible variables in goal positions are
translated to call/1.
As a result, if such a variable is at runtime bound to a (!/0),
the cut is scoped to the call/1
call rather than the enclosing \+/1.
Many Prolog implementations (including SWI-Prolog) provide not/1. The not/1 alternative is deprecated due to its strong link to logical negation.