5.7.18  Mythryl Prefix, Infix, Postfix and Circumfix Operators

Contemporary programming is (perhaps unfortunately) based upon seven-bit ASCII, leading to a distict paucity of available operator symbols, particularly compared with the rich variety used in mathematics.

This paucity is accentuated in SML by the design inability to distinguish between prefix and infix uses of an operator symbol such as -. This forces SML to use tilde for unary negation and ! for dereferencing, in jarring discord with contemporary practice.

C avoids this problem by adopting the rule that every pair of alphabetic identifiers must be separated by a binary symbolic operator; this allows any following symbolic operators to be unambiguously identified as prefix. This is why C can use * for both binary multiplication and unary dereferencing. This design approach is unworkable in the functional programming context due to the pervasive use of f x functional application syntax.

Mythryl, participating in a recent trend, uses the presence or absence of whitespace to distinguish infix from prefix operator application:

    f-g             # Infix --- subtraction.
    f -g            # f(-g).
    f - g           # Infix --- subtraction.
    f- g            # Postfix. (No default Mythryl library semantics.)

This effectively doubles or triples the size of the available operator namespace and allows Mythryl to use default operator definitions which are much more in tune with contemporary C-influenced intuition.

This also allows Mythryl to support some mathematical notations not (yet?) commonly used in the programming community, such as this definition of the factorial function, taken from the Mythryl standard library src/lib/std/src/multiword-int-guts.pkg package:

    fun 0! =>  1;
        n! =>  n * (n - 1)! ;

Mythryl similarly supports a limited set of circumfix operators:

    fun |i| = (i > 0) ?? i :: -i;

This allows certain common mathematical notations to be used in the Mythryl programming context for brevity and readability.

To resolve correctly, such expressions must be surrounded by whitespace and there must be no whitespace between the circumfix operator symbols and the enclosed expression.

The set of such operators currently supported is:

(Although in a nod to quantum mechanics, Mythryl does also support mismatched bracket constructs like like <f| and /g>/. The standard library defines no meanings for these.)

The compiler resolves these operators to equivalent but more conventional names early in the front end, renaming them (|x|) (<x>) (/x/) ({x}) respectively. These names may be used in contexts where the functions involved need to be named independent of immediate application ot a value.

A closely related Mythryl frontend tweak internally resolves a[i] to (_[] early. Defining this as a synonym for the usual vector get operation via code like

    my (_[]): (Vector(X), Int) -> X = inline_t::poly_vector::get_with_boundscheck;

(taken from src/lib/std/src/vector.pkg)

allowing more natural reference to vector elements:

    linux> my
    eval:  v = #[1, 2, 3];

    #[1, 2, 3]

    eval:  v[1];


A matching frontend tweak resolves a[i] = v; to (_[]:=)(a,i,v); Defining (_[]:=) as a synonym for the usual vector set operation via code like

    (_[]:=) = set;

(again from src/lib/std/src/vector.pkg) allows use of traditional notation for setting a vector entry:

    linux> my

    eval:  v = #[1, 2, 3];

    #[1, 2, 3]

    eval:  v[1] := 222;

    #[1, 222, 3]

Comments and suggestions to: