[Previous] [Up] [Next]
Go backward to Arithmetics
Go up to More About Prolog
Go forward to Rewriting Programs Dynamically



You have already encountered the concept of an operator several times. The Prolog clause and term delimiters, :- , . ; -> ( ) are all operators. We can write terms such as predicate(Argt1,Argt2,....), and combine them into clauses because the Prolog interpreter and compiler recognise the operators and use them to rewrite the file.

You have also encountered the use of an operator in the place of a functor in unit Difference Lists and Definite Clause Grammars. The DCG-operator --> is used an recognised as the main component of a rule, but we could just as well have written

rule(s, np, vp).
and made the DCG-interpreter recognise rule instead of -->. As shown by the DCG-example, the operator notation is essentially equivalent to the normal predicate-argument notation (the only difference is that you can tell Prolog a little bit more about how the arguments are related). The point of using an operator as opposed to a functor is usually to make the program more readable. The drawback is that Prolog recognises the functor notation as is, whereas operators have to be declared specifically. If you forget to do so, there will be error messages when the program is loaded.

Declaring Operators

You declare an operator as follows: first in the file must be something that Prolog executes automatically and tells it that the operator exist. You achieve this by writing it as a goal without a head (meaning "always make this true"). The goal calls a built in predicate op/3 which tells Prolog to accept the operator by telling it what it needs to know about it: what is precedence is, its type, and what it looks like.

To understand how these work, it is helpful to look at the values for the predefined operators. The procedure current_op/3 may be called to inspect these, and its arguments are the same of those of op/3. The section Predefined Operators gives a listing of the predefined operators in SICStus Prolog.

The precedence of an operator determines the structure of a term containing several operators. The lower the precedence, the tighter an operator binds its arguments. An operator with a low precedence value will thus be dealt with first insofar as evaluation is concerned. Operators which delimit rules, and determine the overall structure of the program have high precedence values. To make sure that everything from one full stop to the next is deal with as a single clause, the full stop has the highest precedence. For instance, the precedence of * is 400, while that of + is 500. Hence

X is 5 + 3 * 4
would bind X to 17, not 32. Note how the `:-' and `?-' have the highest precedences of the operators we have met so far, and comma the next.

The position and associativity is given by one of the following type specifiers:

xfx    xfy    yfx    binary infix operators
              fx     fy     unary prefix operators
              xf     yf     unary postfix operators
The position of the f in the specifier thus determines the position of the operator in a term; the x and y represent the arguments.

The precedence of an argument is 0 if it is enclosed in brackets or it is an unstructured object; otherwise it is the precedence of the principal functor of the argument. x represents an argument whose precedence is strictly lower than that of the operator, while y represents an argument whose precedence is lower than or equal to that of the operator.

Thus, operators which are not usually iterated within an expression, such as =, =.., and is, are defined as xfx. Operators which may be iterated, and are intended to be left associative, like - and +, are yfx. Iterable right associative operators, like the implication ->, are xfy. Similarly, fy and yf are iterable operators, fx and xf are non-iterable.

For example, since \+ is defined as fy, we can write \+ \+ P. If it had been defined as fx, then we would have to write \+ (\+ P).

Predefined Operators

Operator Associativity Precedence
\== xfx 700 spy fy 900 , xfy 1000 - yfx 500 - fx 500 + yfx 500 + fx 500 / yfx 400 * yfx 400 ; xfy 1100 = xfx 700 < xfx 700 > xfx 700 public fx 1150 is xfx 700 --> xfx 1200 mode fx 1150 ^ xfy 200 =.. xfx 700 nospy fy 900 wait fx 1150 // yfx 400 -> xfy 1050 :- xfx 1200 :- fx 1200 multifile fx 1150 =:= xfx 700 ?- fx 1200 << yfx 400 == xfx 700 @>= xfx 700 >= xfx 700 @=< xfx 700 @< xfx 700 @> xfx 700 =< xfx 700 /\ yfx 500 >> yfx 400 parallel fx 1150 \+ fy 900 \/ yfx 500 =\= xfx 700 dynamic fx 1150 mod xfx 300


[Previous] [Up] [Next]