Skip to content
Polymorphic Variants
step 1/5

Reading — step 1 of 5

Learn

~1 min readFunctors and Polymorphic Variants

Polymorphic variants start with backtick — `Tag. Unlike regular variants, they don't need to be declared in a type definition.

let x = `Red
let y = `Green
let z = `Blue

let describe = function
    | `Red -> "hot"
    | `Green -> "calm"
    | `Blue -> "cool"

describe `Red    (* "hot" *)

No type color = Red | Green | Blue needed.

Tags can carry data:

let shapes = [`Circle 5; `Square 3.0; `Rectangle (4, 7)]

let area = function
    | `Circle r -> 3.14 *. r *. r
    | `Square s -> s *. s
    | `Rectangle (w, h) -> float_of_int (w * h)

The inferred type contains the polymorphic variant tags.

Open vs closed types:

  • [> Red | Blue] — at LEAST these tags (open — can have more)
  • [< Red | Green] — at MOST these tags (closed)
  • [Red | Blue] — EXACTLY these (regular)

The > and < are subtyping relations.

Combining different tag sets:

let basic_color : [> `Red | `Green | `Blue] = `Red
let shade : [> `Light | `Dark] = `Light
let combined = (basic_color, shade)
(* type: [> `Red | `Green | `Blue] * [> `Light | `Dark] *)

This flexibility is poly variants' superpower — extensible types without forcing a hierarchy.

Use cases:

  • Quick prototyping (no type def needed)
  • API responses with growing case sets
  • Exception-like enums

Drawbacks:

  • More complex type errors (subtyping confuses people)
  • Less efficient than regular variants (tags are integer-coded, not pointer-tag)
  • Pattern matching exhaustiveness checking weaker

Most OCaml code uses regular variants. Reach for polymorphic variants when the case set is genuinely open or you're prototyping.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…