You probably have a particular idea of what a "constructor" is from C++. Forget what you know. In general, for any language, a "constructor" is an expression which creates a value of a particular type. Languages commonly support two kinds of types:
ML has built-in constructor functions corresponding to each of the built-in compound types:
x :: xs (* List constructor: 2 components (head, tail) *) (x, y, z) (* Tuple constructor: 3 components (#1, #2, #3) *) {x=p, y=q} (* Record constructor: 2 components (#x, #y) *)
The square bracket constructor [a,b,c]
is just
"syntactic sugar" for the ::
constructor form.
_
pattern),Patterns are used on the "left-hand side" whenever a binding occurs. So far, we know of two places where bindings may occur:
val
bindingsFor function arguments, the "left-hand side" is the formal parameter, and the "right-hand side" is the actual parameter.
Intuitively, "matching" allows us to perform an implicit computation when we bind a value. The computation attempts to answer the question: "Does the thing on the right hand side have a shape and value like the thing on the left-hand side?" (As an incidental bonus, we can bind designated pieces of the right-hand side to identifiers, for later use.) If you think about this intuition for a while, you will see why it makes sense that constructors, and not arbitrary expressions, are allowed in a pattern: constructors unambiguously describe "shapes" of data.
Random historical trivia: the idea of pattern-matching as a style of describing computation comes from Prolog and the family of logic programming languages.