tl;dr
Can triadic (or greater adicity) infix operators be syntactically represented and incorporated into expressions in a general fashion?
If so, how?
And if so, why don’t existing programming languages allow custom triadic infix operators to be defined and employed?
The long read
We’re all familiar with basic dyadic infix operators, such as the addition operator +
in the expression a + b
.
In a functional style of syntax we would represent this as something like ADD(a, b)
.
In C and in C-influenced languages, there is often a triadic conditional operator in the style x ? y : z
, meaning the same as ‘if x then y else z’.
Some languages also incorporate an ‘if’ function, in the style of if(x, y, z)
, with the first operand representing the condition, the second operand the value to be returned if the condition is true, and the third operand the value if the condition is false.
Computer scientist Tony Hoare also came up with a representation of the triadic conditional operator as y ⊲ x ⊳ z
(or in case these Unicode arrows do not represent to the reader properly, the equivalent in ASCII: y <| x |> z
).
The pair of infixed arrows here represent Hoare’s conditional operator syntactically, and serve to separate the operands from one another, in much the same way (but differing in the order of the operands) as the C-style representation.
From what I understand, in programming languages like C that have these triadic conditional operators, they are parsed somehow as special cases, and there is no facility to define custom triadic operators.
In SQL, we have join operators that are (nowadays, following the supersession of an older syntax) represented syntactically in the form of a Join b On a.Id = b.id
.
This syntactical construct is not strictly treated as an expression in SQL (and there is additional syntactical ceremony around these constructs, the presence of which is mandatory for a valid SQL statement, but which I have elided here).
But I have come to understand such join syntax as basically that of a triadic operator, which accepts as operands firstly two tables, and as a third operand an expression which defines a condition that is evaluated for each combination of the rows from each table.
In the theory of relational algebra, these joins are indeed understood as operators, but syntactically they are represented in a form which requires complex mathematical-style typesetting. Typically, the join condition is provided in a smaller font, and as a subscript attached to the join operator symbol. The join operator symbol itself is infixed between two table operands, and appears (notwithstanding the presence of the attached subscript) to be a dyadic operator.
In my view, this mathematical style (besides requiring special facilities to typeset) produces a garbled appearance.
For this reason, SQL was designed so that the expression which represents the join condition falls third in sequence. That is, with the Join
keyword falling between the two table operands, and the On
keyword falling between the second operand (which is the second table) and the third operand (which is the join condition). This ‘On’ keyword is not an independent operator or syntactical element, but is associated with the prior presence of the ‘Join’ keyword.
And for this reason the join syntax in SQL appears, to me at least, to take on the form of being a triadic infix operator, in a similar way structurally as the various representations of the conditional operator in other contexts (and albeit infixing English words, as is a tenet of SQL, rather than infixing symbols).
In SQL, further joins with additional tables can continue be specified in order of evaluation, in the manner of a Join b On a.Id = b.Id Join c On b.Id = c.Id
. The output of the first join, which is itself a table, forms the first operand for the second join.
In a language such as C#, a method which performs one such join could probably be represented in a functional style as Join(a, b, (a,b) => a.Id = b.Id)
. But a series of two or more such joins, within one expression, would entail a mess of syntax and brackets with this functional-style representation.
What I’m interested in is whether there is any systematic approach to the representation of triadic (or higher adicity) infix operators within expressions.
For example, does a system of parsing exist to differentiate a triadic (or greater adicity) operator, from merely a series of two (or more) dyadic operators?
Can the approach which exists to handle the triadic conditional operator, be made to work generically in expressions consisting of any kind of triadic operator (and successfully handle expressions containing mixtures of operators of differing adicities, and resolve ambiguities sensibly)?