Skip to content
Lesson 2 of 7

Step 1 of 5 · Reading · ~2 min

Learn

Functors 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.0; `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)
  • Slightly less efficient than regular variants: a tag is a hash of its name, so a match compares hashes rather than a small dense integer
  • 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.

Up nextLazy ValuesLazy Evaluation and Sequences

Discussion

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

Sign in to post a comment or reply.

Loading…