Many predicates can sensibly be called in different ways, e.g. with a
specific argument as input or as output. The header of the documentation
of a predicate consists of one or more templates, each
representing a specific way of calling the predicate.
A template can contain information about types, argument
instantiation patterns, determinism and more. The syntax is informally
described below:
<template> | ::= | <head>[’//’]’is’ <determinism> |
| | | <head>[’//’] |
<determinism> | ::= | ’det’ |
| | | ’semidet’ |
| | | ’failure’ |
| | | ’nondet’ |
| | | ’multi’ |
| | | ’undefined’ |
<head> | ::= | <functor>’(’<argspec> ’,’ <argspec>’)’ |
| | | <functor> |
<argspec> | ::= | [<instantiation>]<argname>[’:’<type>] |
<instantiation> | ::= | ’++’ | ’+’ | ’-’ | ’--’ | ’?’
| ’:’ | ’@’ | ’!’ |
<type> | ::= | <term> |
The determinism values originate from Mercury. Their meaning
is explained in the table below. Informally, det
is used
for deterministic transformations (e.g. arithmetic), semidet
for tests, nondet
and multi
for generators.
The
failure
indicator is rarely used. It mostly appears in
hooks or the recovery goal of catch/3.
Determinism | Predicate behaviour |
det | Succeeds exactly once
without a choice point |
semidet | Fails or Succeeds exactly once
without a choice-point |
failure | Always fails |
nondet | No constraints on the number of
times the predicate succeeds and whether or not it leaves choice-points
on the last success. |
multi | As nondet , but succeeds
at least one time. |
undefined | Well founded semantics third
value. See undefined/0. |
The meanings of the instantiation patterns for individual
arguments are:
++ | Argument is ground at call-time, i.e., the argument
does not contain a variable anywhere. |
+ | Argument is fully instantiated at call-time, to a term
that satisfies the type. This is not necessarily ground, e.g.,
the term
[_] is a list, although its only member is
unbound. |
- | Argument is an output argument. It may be
unbound at call-time, or it may be bound to a term. In the latter case,
the predicate behaves as if the argument was unbound, and then unified
with that term after the goal succeeds. For example, the goal findall(X,
Goal, [T]) is good style and equivalent to findall(X, Goal,
Xs), Xs = [T] 3The ISO
standard dictates that findall(X, Goal, 1) raises a type_error
exception, breaking this semantic relation. SWI-Prolog does not follow
the standard here. Determinism declarations assume that the
argument is a free variable at call-time. For the case where the
argument is bound or involved in constraints,
det effectively becomes semidet , and multi
effectively becomes nondet . |
-- | Argument is unbound at call-time. Typically used by
predicates that create‘something’and return a handle to the
created object, such as open/3
which creates a stream. |
? | Argument is bound to a partial term of the
indicated type at call-time. Note that a variable is a partial term for
any type. |
: | Argument is a meta-argument. Implies + . |
@ | Argument will not be further instantiated than it is
at call-time. Typically used for type tests. |
! | Argument contains a mutable structure that may be
modified using
setarg/3 or nb_setarg/3. |
Users should be aware that calling a predicate with arguments
instantiated in a way other than specified by one of the templates may
result in errors or unexpected behavior.
Developers should ensure that predicates are steadfast with
respect to output arguments (marked - in the template). This means that
instantiation of output arguments at call-time does not change the
semantics of the goal (it may be used for optimization, though). If this
steadfast behavior cannot be guaranteed, -- should be used instead.
In the current version, argument types are represented by an
arbitrary term without formal semantics. In future versions we may adopt
a formal type system that allows for runtime verification and static
type analysis
Hermenegildo,
2000, Mycroft &
O'Keefe, 1984, Jeffery et
al., 2000
Examples
%! length(+List:list, -Length:int) is det.
%! length(?List:list, -Length:int) is nondet.
%! length(?List:list, +Length:int) is det.
%
% True if List is a list of length Length.
%
% @compat iso