Standard ML has special syntax for products (tuples). A product type is written as

t1 * t2 * ... * tN

and a product pattern is written as

(p1, p2, ..., pN)

In most situations the syntax is quite convenient. However, there are situations where the syntax is cumbersome. There are also situations in which it is useful to construct and destruct n-ary products inductively, especially when using Fold.

In such situations, it is useful to have a binary product datatype with an infix constructor defined as follows.

datatype ('a, 'b) product = & of 'a * 'b
infix &

With these definitions, one can write an n-ary product as a nested binary product quite conveniently.

x1 & x2 & ... & xn

Because of left associativity, this is the same as

(((x1 & x2) & ...) & xn)

Because & is a constructor, the syntax can also be used for patterns.

The symbol & is inspired by the Curry-Howard isomorphism: the proof of a conjunction (A & B) is a pair of proofs (a, b).

Example: parser combinators

A typical parser combinator library provides a combinator that has a type of the form.

'a parser * 'b parser -> ('a * 'b) parser

and produces a parser for the concatenation of two parsers. When more than two parsers are concatenated, the result of the resulting parser is a nested structure of pairs

(...((p1, p2), p3)..., pN)

which is somewhat cumbersome.

By using a product type, the type of the concatenation combinator then becomes

'a parser * 'b parser -> ('a, 'b) product parser

While this doesn’t stop the nesting, it makes the pattern significantly easier to write. Instead of

(...((p1, p2), p3)..., pN)

the pattern is written as

p1 & p2 & p3 & ... & pN

which is considerably more concise.

Also see