When programming in Prolog it is not always possible, or desirable, to create predicates which unify for every possible combination of parameters. For example, the predicate between(X,Y,Z)
which expresses that Z is numerically between X and Y. It is easily implemented in the cases where X, Y, and Z are all bound (either Z is between X and Y or it is not), or where X and Y are bound and Z is free (Z unifies with all numbers between X and Y, or the predicate fails if Y<X); but in other cases, such as where X and Z are bound and Y is free, there are potentially an infinite number of unifications. Although this can be implemented, it usually would not be.
Flow declaration or mode declarations allow an explicit description of how predicates behave when called with different combinations of bound parameters. In the case of between
, the declaration would be:
%! between(+X,+Y,+Z) is semidet.
%! between(+X,+Y,-Z) is nondet.
Each line specifies one potential calling pattern for the predicate. Each argument is decorated with +
to indicate cases where it is bound, or -
to indicate cases where it is not (there are also other decorations available for more complex types such as tuples or lists that may be partially bound). The keyword after is indicates the behavior of the predicate in that case, and may be one of these:
det
if the predicate always succeeds with no choice point. For example add(+X,+Y,-Z)
is det
because adding two given numbers X and Y will always have exactly one answer.semidet
if the predicate either succeeds or fails, with no choice point. As above, between(+X,+Y,+Z)
is semidet
because Z is either between X and Y or it is not.multi
if the predicate always succeeds, but may have choice points (but also may not). For example, factor(+X,-Y)
would be multi
because a number always has at least one factor - itself - but may have more.nondet
if the predicate may succeed with choice points, or fail. For example, between(+X,+Y,-Z)
is nondet
because there may be several possible unifications of Z to numbers between X and Y, or if Y<X then there are no numbers between them and the predicate fails.Flow/mode declarations can also be combined with argument labeling to clarify what terms mean, or with typing. For example, between(+From:Int, +To:Int, +Mid:Int) is semidet
.
In pure Prologs, flow and mode declarations are optional and only used for documentation generation, but they can be extremely useful to help programmers identify the cause of instantiation errors.
In Mercury, flow and mode declarations (and types) are mandatory and are validated by the compiler. The syntax used is as above.
In Visual Prolog, flow and mode declarations and types are also mandatory and the syntax is different. The above declaration would be written as:
between : (int From, int To, int Mid) determ (i,i,i) nondeterm (i,i,o).
The meaning is the same as above, but with the differences that:
i
and o
are used for +
and -
and are matched with the parameters based on ordering;det
becomes procedure
, semidet
becomes determ
, and nondet
becomes nondeterm
(multi
is still multi
).