Skip to content
Part IA Michaelmas Term

Constructors with Arguments

Carrying data

OCaml generalises enumeration types by allowing constructors to carry data:

type vehicle = Bike
             | Motorbike of int   (* engine size in CCs *)
             | Car       of bool  (* true if a Reliant Robin *)
             | Lorry     of int   (* number of wheels *)
  • Bike is a constant constructor: it is a value by itself.
  • Motorbike 450 is a vehicle constructed from the integer 450.
  • Car true and Car false are distinct vehicles from the same constructor.
  • Motorbike of int and Lorry of int are distinct types: even though both carry an int, OCaml tracks which constructor was used. Motorbike 450 is never confused with Lorry 450.

Pattern matching with arguments

Constructors carrying data can be destructured in patterns:

let wheels = function
  | Bike -> 2
  | Motorbike _ -> 2           (* discard the engine size *)
  | Car robin -> if robin then 3 else 4  (* bind to robin *)
  | Lorry w -> w               (* extract the wheel count *)

Pattern elements:

  • Named variable (robin, w): binds the carried value for use in the right-hand side.
  • Wildcard _: matches any carried value and discards it. The underscore signals that the argument is irrelevant to the computation.

Mixed-type-like lists

Datatypes with constructors carrying different payload types allow heterogeneous collections:

[Bike; Car true; Motorbike 450]

This is a vehicle list. It behaves almost like a mixed-type list containing integers and booleans. The datatype mechanism reduces the impact of the restriction that all list elements must share the same type.

Nested patterns

Patterns can be as complex as needed and may combine constructors from multiple datatypes. For example, patterns can deconstruct lists and vehicles simultaneously, or match integer and string constants inside constructors. OCaml compiles pattern matching efficiently.