OCaml Expert · Lesson 1 · On the house

GADTs

Generalized algebraic data types, typed expression evaluators, and type refinement. Lesson 1 is free — on the house.

Lessons · OCaml Expert · Lesson 1 of 10 · On the house

GADTs

Generalized algebraic data types, typed expression evaluators, and type refinement.

Illustration for OCaml
Lesson 1 is on the house.

A GADT lets each constructor fix the type parameter: type _ expr = Int : int -> int expr | Bool : bool -> bool expr | Add : int expr * int expr -> int expr | If : bool expr * 'a expr * 'a expr -> 'a expr.

Matching a constructor refines the type: in the Int n branch, the compiler knows 'a = int. That is how eval : type a. a expr -> a returns an int in one branch and a bool in another.

The annotation type a. introduces a locally abstract type and makes the function polymorphic in it, which GADT matching needs.

Ill-typed programs cannot be built: Add (Bool true, Int 1) is rejected at compile time, so eval needs no runtime type checks.

GADTs also encode existential types (hiding a type inside a constructor) and type-safe printf-style formats.

GADT eval

type _ expr =
  | Int : int -> int expr
  | Bool : bool -> bool expr
  | Add : int expr * int expr -> int expr
  | If : bool expr * 'a expr * 'a expr -> 'a expr
  | Eq : int expr * int expr -> bool expr

let rec eval : type a. a expr -> a = function
  | Int n -> n
  | Bool b -> b
  | Add (x, y) -> eval x + eval y
  | If (c, t, e) -> if eval c then eval t else eval e
  | Eq (x, y) -> eval x = eval y

let () =
  print_endline (string_of_int (eval (If (Eq (Int 2, Add (Int 1, Int 1)), Int 10, Int 20))));
  print_endline (string_of_bool (eval (Eq (Int 1, Int 2))))
Match this when you type.

Quiz

What does matching Int n refine?

Quiz

Why does eval need type a. a expr -> a?

Quiz

What happens with Add (Bool true, Int 1)?

Quiz

What does the first line print?

Check

Match the still for: GADTs.

Open-book: the answers are on this page. Pass every quiz and check (5) to mark the lesson done. This visit: 0/5.