Prolog Language Using Modern Prolog Flow/mode declarations


Example

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:

  • The flow/mode declarations are separated from the type declarations (since it is assumed that flow/mode for a single predicate will not vary with type overloading);
  • i and o are used for + and - and are matched with the parameters based on ordering;
  • The terms used are different. det becomes procedure, semidet becomes determ, and nondet becomes nondeterm (multi is still multi).