Polymorphic Variants

Polymorphic variants start with a backtick and don't need a type declaration:

26.1 Syntax

Polymorphic variants start with a backtick and don't need a type declaration:

let color_to_int = function
  | `Red -> 0
  | `Green -> 1
  | `Blue -> 2
(* val color_to_int : [< `Blue | `Green | `Red ] -> int *)

let x = `Point (1, 2)     (* [> `Point of int * int ] *)

26.2 Open and closed types

[ \A | \B ] exactly A or B [> \A | \B ] at least A and B (open — can be extended) [< \A | \B ] at most A and B (subset)

[< \A | \B > \A ]` | at most A,B; at least A

26.3 Declaring and combining

type basic = [ `Red | `Green | `Blue ]
type extended = [ basic | `Black | `White ]

let to_string : [< extended ] -> string = function
  | #basic -> "basic color"         (* #basic matches any basic constructor *)
  | `Black -> "black"
  | `White -> "white"

26.4 Subtyping and coercion

let b : basic = `Red
let e : extended = (b :> extended)

26.5 Use cases

Composable error types: [ \Not_found | \Permission_denied ] merged across libraries.

Lightweight enumerations, tagging, HTTP methods in web libraries.

let read_file path : (string, [> `Not_found of string ]) result = ...
let parse s : (int, [> `Parse_error ]) result = ...
(* Using both in one function yields [> `Not_found of string | `Parse_error ] automatically *)

26.6 Trade-offs

Pros: flexible, extensible, no declarations. Cons: worse error messages, typos create new tags, less exhaustiveness help when open. Prefer regular variants unless you need the flexibility.