The specifier of an operator denotes the class (prefix, infix, postfix) and associativity of an operator.
xfx
means that the operator does not permit any form of associativity. In other words: it does not nest with operators of the same priority. However, it does still nest with operators of a lower priority.
The largest part of such operators are predicates of arity two that are used for comparison-like meaning and where nesting would have - at least - an entirely different meaning than what the predicate is about. They are all located at priority 700: High enough to allow all arithmetic operators to work without bracketing ; low enough to work with control constructs and related meta-predicates that expect goals as arguments. Think of (\+)/1
, (;)/2
, (',')/2
.
Consider =<
: If you want to state that X
is between 1 and 3 you cannot write 1 =< X =< 3
because neither (1 =< X) =< 3
nor 1 =< (X =< 3)
make sense in Prolog. In fact, both would lead to an evaluation error. You have to write 1 =< X, X =< 3
. which means =<(1, X), =<(X, 3)
.
For some cases it might make sense to nest, think of (A = B) = P
. Here, the first =
is just a functor like any other of arity 2, while the second =
is the built-in predicate (=)/2
for equality/unification. But such cases are rare and it is worth highlighting them with an extra pair of round brackets.
Note also that :- :- a.
is invalid syntax, because (:-)/1
again does not nest.
Arithmetic operators are typically left associative since you process them left-to-right like 1+2+4
, first computing 1+2
and only then adding 4
. The notable exception is (^)/2
: This is so, because (X^Y)^Z =:= X^(Y*Z)
whereas (X^(Y^Z))
denotes a term that cannot be expressed with simpler operators.