Skip to content

Polymorphic variants

Pattern matching polymorphic variants has some extra capabilities that you should be aware of. This occurs in the compilers starting from assignment 3 when operators are defined in terms of different polymorphic variant types:

type base_op = [
  | `Read
  | `Add
  | `Sub
  | `Negate
  | `Not
]

type cmp_op = [
  | `Eq
  | `Lt
  | `Le
  | `Gt
  | `Ge
] 

type core_op = [
  | base_op
  | cmp_op
]

As you can see, you can define core_op as the union of two other polymorphic variant types without defining a new constructor. (This is something you can't do with regular algebraic datatypes.) But when you are pattern-matching on core_op values (which can have any of the constructors of base_op or cmp_op) you may need to split them back into the two classes. This is done rather easily:

match (op : core_op) with  (* type annotation is optional *)
  | #base_op as b_op ->    (* your code with (b_op : base_op) *)
  | #cmp_op as c_op ->     (* your code with (c_op : cmp_op) *)

The new syntax #base_op as b_op (or #cmp_op as c_op) will match any of the base_op (or cmp_op) constructors, and you can then do whatever you want with those.

This is described (somewhat briefly) in the OCaml manual:

To make this even more comfortable, you may use type definitions as abbreviations for or-patterns. That is, if you have defined type myvariant = [`Tag1 of int | `Tag2 of bool], then the pattern #myvariant is equivalent to writing (`Tag1(_ : int) | `Tag2(_ : bool)).