[   ^ to index...   |   next -->   ]

CSE 341 : 12 April 2001

Constructors

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:

  1. atomic types, which typically include scalars (numbers) and strings. Constructors for atomic types are typically just a syntactic representation of the atomic value: "hello", 1, 3.14159, etc.
  2. compound types, whose values are created by applying constructor functions to other types. In a properly orthogonal language, the types of a compound type's components may also be compound types. In this fashion, users can build up types of arbitrary complexity.

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.

Patterns

    A pattern is either:
  1. a constant (i.e., an atomic constructor),
  2. a variable,
  3. a wildcard (the special _ pattern),
  4. a constructor applied to one or more patterns

Patterns are used on the "left-hand side" whenever a binding occurs. So far, we know of two places where bindings may occur:

  1. val bindings
  2. function arguments

For 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.


Keunwoo Lee
Last modified: Thu May 10 15:00:57 PDT 2001