Operators in Prolog are simply a notational convenience. For
example, the expression 2+1
could also be written +(2,1)
.
This expression represents the compound term
+ / \ 2 1
and not the number 3. The addition would only be performed if
the term were passed as an argument to an appropriate predicate such as
is/2
(see Arithmetic).
The Prolog syntax caters for operators of three main kinds--infix, prefix and postfix. An infix operator appears between its two arguments, while a prefix operator precedes its single argument and a postfix operator is written after its single argument.
Each operator has a precedence, which is a number from 1 to 1200. The
precedence is used to disambiguate expressions where the structure of
the term denoted is not made explicit through the use of parentheses.
The general rule is that it is the operator with the highest
precedence that is the principal functor. Thus if +
has a higher
precedence than /
, then
a+b/c a+(b/c)
are equivalent and denote the term +(a,/(b,c))
. Note that the
infix form of the term /(+(a,b),c)
must be written with explicit
parentheses, i.e.
(a+b)/c
If there are two operators in the subexpression having the same highest precedence, the ambiguity must be resolved from the types of the operators. The possible types for an infix operator are
xfx xfy yfx
Operators of type xfx
are not associative: it is a requirement
that both of the two subexpressions which are the arguments of the
operator must be of lower precedence than the operator itself,
i.e. their principal functors must be of lower precedence, unless the
subexpression is explicitly parenthesized (which gives it zero
precedence).
Operators of type xfy
are right-associative: only the first
(left-hand) subexpression must be of lower precedence; the right-hand
subexpression can be of the same precedence as the main operator.
Left-associative operators (type yfx
) are the other way around.
A functor named name is declared as an operator of type type and precedence precedence by the directive:
:- op(precedence, type, name).
The argument name can also be a list of names of operators of the same type and precedence.
It is possible to have more than one operator of the same name, so long as they are of different kinds, i.e. infix, prefix or postfix. Note that the ISO Prolog standard contains a limitation that there should be no infix and postfix operators with the same name, however, SICStus Prolog lifts this restriction.
An
operator of any kind may be redefined by a new declaration of the same
kind. This applies equally to operators which are provided as standard,
except for the ','
operator.
Declarations of all the standard operators can be found elsewhere
(see Standard Operators).
For example, the standard operators +
and -
are declared by
:- op(500, yfx, [ +, - ]).
so that
a-b+c
is valid syntax, and means
(a-b)+c
i.e.
+ / \ - c / \ a b
The list functor ./2
is not a standard operator, but if we
declare it thus:
:- op(900, xfy, .).
then a.b.c
would represent the compound term
. / \ a . / \ b c
Contrasting this with the diagram above for a-b+c
shows the
difference between yfx
operators where the tree grows to the
left, and xfy
operators where it grows to the right. The tree
cannot grow at all for xfx
operators; it is simply illegal to
combine xfx
operators having equal precedences in this way.
The possible types for a prefix operator are
fx fy
and for a postfix operator they are
xf yf
The meaning of the types should be clear by analogy with those for infix
operators. As an example, if not
were declared as a prefix
operator of type fy
, then
not not P
would be a permissible way to write not(not(P))
. If the type
were fx
, the preceding expression would not be legal, although
not P
would still be a permissible form for not(P)
.
If these precedence and associativity rules seem rather complex, remember that you can always use parentheses when in any doubt.
Note that the arguments of a compound term written in standard syntax
must be expressions of precedence below 1000. Thus it is
necessary to parenthesize the expression P :- Q
in
| ?- assert((P :- Q)).