Previous Up Next

3  Compilation

In this section, we present a compilation scheme close to the one described in  [20, 1], and implemented in compilers such as the hbc compiler or the Objective Caml compiler. This classical scheme will be refined later into an optimized scheme, using same notations and concepts.

3.1  Output of the match compiler

The compilation of pattern-matching is described by the scheme C that maps a clause matrix to a lambda-code expression. We now describe the specific lambda-code constructs that the scheme C outputs while compiling patterns.

3.2  Initial state

Input to the pattern matching compiler C consists of two arguments: a vector of variables x of size n and a clause matrix PL of width n and height m.

x = (x1  x2xn),    PL =




  p11   p21  ⋯  pn1  →  l1
  p12   p22  ⋯  pn2  →  l2
  p1m   p2m  ⋯  pnm  →  lm






The initial matrix is generated from source input. Given a pattern-matching expression (in Caml syntax):
  match x  with | p1 -> e1 | p2 -> e2 …  | pm -> em
The initial call to C is:
  catch    C((x), (
  p1  →  l1
  p2  →  l2
     →   
  pm  →  lm
))      with (failwith "Partial match")

Where the li's are the translations to lambda-code of the ei's, and (failwith "Partial match") is a runtime failure that occurs when the whole pattern matching fails.

3.3  Classical scheme

By contrast with previous presentations, we assume that matrix PL has at least one row (i.e. m > 0). This condition simplifies our presentation, without restricting its generality. Hence, scheme C is defined by cases on non-empty clause matrices:
  1. If n is zero (i.e. when there are no more columns), then the first row of P matches the empty vector ():
    C((),




         →  l1
         →  l2
         →  lm




    ) = l1


  2. If n is not zero, then a simple compilation is possible, using the following four rules.
    1. If all patterns in the first column of p are variables, y1, y2, ..., ym, then:
      C(x, PL) = C((x2  x3xn), P' → L')
      where
      P' → L' =




      p21 pn1  →  let (y1 x1) l1
      p22 pn2  →  let (y2 x1) l2
      p2m pnm  →  let (ym x1) lm




      )
      We call this rule, the variable rule. This case also handles wild-card patterns: they are treated like variables except that the let-binding is omitted.

    2. If all patterns in the first column of P are constructor patterns c(q1, … , qa), then let C be the set of matched constructors, that is, the set of the head constructors of the p1i's.

      Then, for each constructor c in C, we define the specialized clause matrix S(c,PL) by mapping the following transformation on the rows of P.
      p1i S(c,PL)
      c(q1i, … , qai) q1i  ⋯ qai p2i  ⋯ pni li
      c'(q1i, … , qa'i)   (c' ≠ c)      No row
      (Matrices S(c,PL) and PL define the same matching predicate when x1 is bound to some value c(v1, … , va).) Furthermore, for a given constructor c of arity a, let y1, … ,ya be fresh variables. Then, for any constructor c in C, we define the lambda-expression r(c):
        (let (y1 (field 0 x1))    ...    (ya (field (a−1)  x1))    C((y1, … ,ya,x2, … ,xn),S(c,PL)))

      Finally, assuming C = {c1,…, ck}, the compilation result is:
        switch x1  with    case c1: r(c1)case ck: r(ck)    default: exit
      (Note that the default clause can be omitted when C makes up a full signature.) We call this rule, the constructor rule.

    3. If P has only one row and that this row starts with an or-pattern:
      P =

        (q1 ∣... ∣qo)   p2  ⋯  pn  →  l

      ,


      Then, compilation result is:
      C((x1),



        q1  →  ()
        qo  →  ()



      ); C( (x2xn), ( p2pnl ))
      This rule is the orpat rule. Observe that it does not duplicate any pattern nor action. However, variables in or-patterns are not supported, since, in clause qi → (), the scope of qi variables is the action “()”.

    4. Finally, if none of the previous rules applies, the clause matrix PL is cut in two clause matrices P1L1 and P2L2, such that P1L1 is the largest prefix of PL for which one of the variable, constructor or orpat rule applies.

      Then, compilation result is:
        catch C(x, P1L1 with C(x, P2L2)
      This rule is the mixture rule.
This paper doesn't deal with optimizing let-bindings, which are carelessly introduced by scheme C. This job is left to a later compilation phase.


Previous Up Next