prologoperator-precedenceiso-prolog

Minor inconsistency due to different operator precedence of ** and ^


Why is argument precendence of **/2 (xfx) and (^)/2 (xfy) not the same in Prolog?

This causes minor inconsistencies, such as the following:

?- X = 1, Y is 1 ^ -X.
X = Y, Y = 1.

and:

?- Y is 1 ** -1.
Y = 1.

but:

?- X = 1, Y is 1 ** -X.
ERROR: Syntax error: Operator priority clash
ERROR: X = 1, Y is 1 *
ERROR: ** here **
ERROR: * -X .

Solution

  • Minor point: It's (^)/2 and not ^/2 to indicate that ^ is used as an operator and to make it valid Prolog syntax and a predicate indicator (7.1.6.6).

    (**)/2 and (^)/2 are both evaluable functors (9), so they can be used for Arithmetic evaluation (8.7) with (is)/2 and Arithmetic comparison (8.7) with (=:=)/2, (<)/2 and the like. Their definitions differ slightly.

    (**)/2 always gives back a float in the same way as (/)/2 always gives a float. (SWI does not follow the standard here, it has its own conventions).

    ?- X is 2**2.
       X = 4.0.
    ?- X is 2/2.
       X = 1.0.
    

    (^)/2 is here to permit integer exponentiation which has become much more important with many systems now supporting arbitrarily large integers. Think of 2^2^X. That is, if both arguments are integers, the result is an integer as well, in the same way that (*)/2 handles this case.

    ?- X is 2^2, Y is 2*2.
       X = 4, Y = 4.
    ?- X is 2.0^2, Y is 2.0*2.
       X = 4.0, Y = 4.0.
    

    In those cases where (^)/2 would give a real value with two integer arguments (like 2^ -1), a type error is produced, and then there are more errors for otherwise complex or undefined results.

    (^)/2 was used for exponentiation for quite some time. An early use of the exponentiation operator is in D.H.D. Warren's Thesis of 1977 in the example for symbolic differentiation. (It is at least not mentioned in Philippe Roussel's 1975 manual). Throughout the thesis and the 1978 User's guide, the ~ character is used consistently where one would expect a ^ like in integers are restricted to the range -2~17 to 2~17-1 , ie. -131072 to 131071. The declaration was the following and is unchanged since 1982.

    :- op(300, xfy, ~).  % 1977
    :- op(200, xfy, ^).  % 1982 - today
    

    From 1982 on, it was used in quantification of setof/3 and bagof/3 but also as lambdas in natural language parsers. For all these uses it already had the right associativity and priority. As an evaluable functor it was present in several systems.

    The first system to use (^)/2 as an evaluable functor meaning power is probably C-Prolog.

    Compared to this heritage, the (**)/2 appeared in Prolog relatively late, most probably inspired by Fortran. It was proposed for inclusion (N80 1991-07, Paris papers) shortly before the first Committee Draft (CD 1992). Systems provided it also as exp/2.

    (**)/2 has the same priority as (^)/2 but does not have any associativity, which at first might strike as odd, since there are quite some cases, where it is common to have exponentiation twice. Most prominently, the Gaussian function in its simplest form

    e-x2

    Instead of using the constant e and exponentiation, a special evaluable functor exp/1 is provided. Above is thus written as exp(- X**2). In fact, also Wikipedia uses this notation. Given this functor, there are no needs for associativity in this common case.

    Should there actually be one, I would be very interested to see it.

    Compared to other systems it seems quite common to offer two kinds of exponentiation. Think of Haskell which has ^ and **.

    To conclude: There does not seem to be a frequent case where nested float exponentiation is needed. So minimal support seems to be preferable.