Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

OCaml  Module 4 – Tuples, records, variants and pattern matching

Variants, options and recursive types

Define OCaml variant types, return option instead of null, build trees and expression types that refer to themselves, and write functions that follow them.

  • Beginner
  • 5 minutes
  • Examples run with ocaml 5.5.1, opam 2.6.0, dune 3.24.2 and Python 3.14.8
  • By MySmartCoPilot
Free lesson, Pro answers: 5 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Define variant types with constant constructors and constructors that carry values
  • Use option for a missing result and handle both of its cases with pattern matching
  • Define recursive and parameterised types such as a binary tree and an expression tree
  • Write recursive functions that follow the shape of their type, one case per constructor

Before you start

What you’ll learn · Before you start

What you will learn

  • Define variant types with constant constructors and constructors that carry values
  • Use option for a missing result and handle both of its cases with pattern matching
  • Define recursive and parameterised types such as a binary tree and an expression tree
  • Write recursive functions that follow the shape of their type, one case per constructor

Before you start

On this page

List.nth [10; 20] 5 stops with Exception: Failure "nth", while List.nth_opt [10; 20] 5 returns None, a value the caller must handle before it can use the answer. Both rely on variant types, OCaml’s way of saying “one of these cases”, and the same idea describes trees and whole expressions.

You will define variants with and without data, use option where other languages use null, declare types that refer to themselves, and write functions with one case per constructor, which the compiler checks for you.

A variant lists the cases a value can be

A variant type: A type that lists every form its values can take, each a constructor, such as type shape = Circle of float | Dot. names every form a value may take. Each form is a constructor: A capitalised name such as Some or Circle that builds one case of a variant type, with or without values inside, and names that case in patterns., written with a capital letter: Dot carries nothing, Circle carries a float, and Rect carries an inline record with fields w and h. A match, or a function with one case per constructor, takes the value apart:

A shape variant, its area, and a forgotten constructor Python · shapes_session.py
from session import toplevel, write

# A variant type lists its cases. A constructor may carry values, here a float or an inline record, or nothing. A match
# that leaves a constructor out draws warning 8 with an example, and a constructor is not a function.
write("shapes.ml", """type shape = Circle of float | Rect of { w : float; h : float } | Dot

let area = function
  | Circle r -> Float.pi *. r *. r
  | Rect { w; h } -> w *. h
  | Dot -> 0.
""")
toplevel("""
#use "shapes.ml";;
List.map area [Circle 1.; Rect { w = 2.; h = 3. }; Dot];;
List.map Circle [1.; 2.];;
List.map (fun r -> Circle r) [1.; 2.];;
type colour = Red | Green | Blue;;
let name = function Red -> "red" | Green -> "green";;
type t = A | B of int | C;;
compare C (B 0);;
""")

Output

$ ocaml
OCaml version 5.5.1
Enter #help;; for help.

# #use "shapes.ml";;
type shape = Circle of float | Rect of { w : float; h : float; } | Dot
val area : shape -> float = <fun>
# List.map area [Circle 1.; Rect { w = 2.; h = 3. }; Dot];;
- : float list = [3.14159265358979312; 6.; 0.]
# List.map Circle [1.; 2.];;
Line 1, characters 9-15:
1 | List.map Circle [1.; 2.];;
             ^^^^^^
Error: This expression should not be a constructor, the expected type is
       'a -> 'b
# List.map (fun r -> Circle r) [1.; 2.];;
- : shape list = [Circle 1.; Circle 2.]
# type colour = Red | Green | Blue;;
type colour = Red | Green | Blue
# let name = function Red -> "red" | Green -> "green";;
Line 1, characters 11-51:
1 | let name = function Red -> "red" | Green -> "green";;
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Warning 8 [partial-match]: this pattern-matching is not exhaustive.
  Here is an example of a case that is not matched: Blue

val name : colour -> string = <fun>
# type t = A | B of int | C;;
type t = A | B of int | C
# compare C (B 0);;
- : int = -1

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 shapes_session.py

area gave 3.14159265358979312 for Circle 1., 6. for the rectangle and 0. for Dot. Two details stand out. A constructor is not a function: List.map Circle [1.; 2.] was refused, “This expression should not be a constructor”, while fun r -> Circle r worked. And the compiler checks that every case is handled. name matched Red and Green but not Blue, and OCaml answered with “Warning 8 [partial-match]: this pattern-matching is not exhaustive”, followed by an example of a value that is not matched, Blue.

The last line is a trap for later. The built-in compare orders constructors without arguments before those with arguments, whatever the order of declaration: for type t = A | B of int | C, compare C (B 0) was -1. Write your own comparison when the order means something in your domain.

Ignoring warning 8

Wrong: leaving name as it is because it compiles. Right: add the missing case, | Blue -> "blue". A value Blue would otherwise raise Match_failure at run time, which is exactly what the warning predicted.

option makes a missing answer part of the type

There is no null in OCaml. A function that may have no answer returns an option: The standard variant type 'a option = None | Some of 'a, used for a result that may be missing instead of a null value., which the standard library defines as an ordinary variant: #show_type option printed type 'a option = None | Some of 'a. The caller receives None or Some value and has to look:

List.nth and nth_opt, safe_div, and handling both cases Python · option_session.py
from session import toplevel

# option is an ordinary variant of the standard library: None or Some value. A function that may have no answer returns
# one, and the caller must handle both cases; List.nth raises an exception where List.nth_opt returns None.
toplevel("""
#show_type option;;
List.nth [10; 20] 5;;
List.nth_opt [10; 20] 5;;
List.nth_opt [10; 20] 1;;
let safe_div a b = if b = 0 then None else Some (a / b);;
(safe_div 7 2, safe_div 7 0);;
let describe = function None -> "no answer" | Some q -> "quotient " ^ string_of_int q;;
describe (safe_div 7 0);;
Option.value ~default:0 (safe_div 7 0);;
Option.map (fun q -> q * 10) (safe_div 7 2);;
safe_div 7 2 + 1;;
""")

Output

$ ocaml
OCaml version 5.5.1
Enter #help;; for help.

# #show_type option;;
type 'a option = None | Some of 'a
# List.nth [10; 20] 5;;
Exception: Failure "nth".
# List.nth_opt [10; 20] 5;;
- : int option = None
# List.nth_opt [10; 20] 1;;
- : int option = Some 20
# let safe_div a b = if b = 0 then None else Some (a / b);;
val safe_div : int -> int -> int option = <fun>
# (safe_div 7 2, safe_div 7 0);;
- : int option * int option = (Some 3, None)
# let describe = function None -> "no answer" | Some q -> "quotient " ^ string_of_int q;;
val describe : int option -> string = <fun>
# describe (safe_div 7 0);;
- : string = "no answer"
# Option.value ~default:0 (safe_div 7 0);;
- : int = 0
# Option.map (fun q -> q * 10) (safe_div 7 2);;
- : int option = Some 30
# safe_div 7 2 + 1;;
Line 1, characters 0-12:
1 | safe_div 7 2 + 1;;
    ^^^^^^^^^^^^
Error: This expression has type int option
       but an expression was expected of type int

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 option_session.py

List.nth [10; 20] 5 raised Failure "nth", an exception the caller may forget to catch; List.nth_opt returned None for position 5 and Some 20 for position 1. safe_div 7 2 gave Some 3 and safe_div 7 0 gave None. The type does the reminding: safe_div 7 2 + 1 was refused, because an int option is not an int.

To get an int out of an int option Gives for None
a match with a None case and a Some q case whatever the None case says
Option.value ~default:0 o 0
Option.map (fun q -> q * 10) o None, still an option

describe handled both cases with a match, Option.value ~default:0 turned None into 0, and Option.map applied a function inside: Some 3 became Some 30.

Key idea

A variant names every case and the compiler checks that each one is handled; option is the variant for “maybe no answer”, so a missing result can never be used by accident.

Checkpoint

Check: Variants and constructors · option instead of null

  1. Question 1 of 2 type colour = Red | Green | Blue and let name = function Red -> "red" | Green -> "green". What does OCaml do?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: It accepts name with warning 8 and gives Blue as an example of an unmatched value

    The session printed "Warning 8 [partial-match]: this pattern-matching is not exhaustive" with the example Blue. Adding | Blue -> "blue" makes the match complete.

  2. Question 2 of 2 safe_div has the type int -> int -> int option. Why is safe_div 7 2 + 1 refused?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: An int option is not an int; the Some or None must be handled before adding

    Use a match, Option.value ~default or Option.map to get from int option to int or to keep working inside the option.

A type can refer to itself, and take a type parameter

A recursive type: A type whose definition refers to itself, such as a tree whose Node constructor holds two smaller trees. mentions itself in one of its constructors. A binary tree is either empty, Leaf, or a Node holding a left tree, a value and a right tree; the parameter 'a lets the same type hold ints, strings or anything else, written 'a tree. Inserting 5, 3, 8 and 1 into a binary search tree keeps smaller values on the left. Step through the insertions:

Interactive · step through it 5, 3, 8 and 1 inserted into a search tree Each key walks down from the root, left when smaller and right when larger, to an empty place.
Binary search tree, keys in order: none; root none.empty tree
  • being compared or looked at
  • being moved or written
  • visited or ruled out

Pseudo-code

  1. insert(x): if the tree is empty: x becomes the root
  2. curr ← root
  3. loop: if x < curr.key: go left, else go right (equal keys go right)
  4. if that child is empty: put x there; stop

Insert 4 keys one at a time. Every key goes left of a node with a larger key and right of a node with a smaller (or equal) key, so an in-order walk lists the keys sorted.

When it finishes: In order: 1 3 5 8.

Comparisons 0
Height -1

The session builds the same tree with the type and its functions, then the tree a sorted input gives:

A search tree of ints, its size and height, and sorted input Python · tree_session.py
from session import toplevel, write

# A recursive, parameterised type: an 'a tree is a Leaf or a Node holding a left tree, a value and a right tree. Each
# function has one case per constructor and calls itself where the type refers to itself.
write("tree.ml", """type 'a tree = Leaf | Node of 'a tree * 'a * 'a tree

let rec insert x = function
  | Leaf -> Node (Leaf, x, Leaf)
  | Node (l, v, r) as t ->
      if x < v then Node (insert x l, v, r)
      else if x > v then Node (l, v, insert x r)
      else t

let rec to_list = function
  | Leaf -> []
  | Node (l, v, r) -> to_list l @ [v] @ to_list r

let rec size = function Leaf -> 0 | Node (l, _, r) -> size l + 1 + size r

let rec height = function Leaf -> 0 | Node (l, _, r) -> 1 + max (height l) (height r)
""")
toplevel("""
#use "tree.ml";;
let t = List.fold_left (fun t x -> insert x t) Leaf [5; 3; 8; 1];;
to_list t;;
(size t, height t);;
let sorted = List.fold_left (fun t x -> insert x t) Leaf [1; 2; 3; 4; 5];;
(size sorted, height sorted);;
""")

Output

$ ocaml
OCaml version 5.5.1
Enter #help;; for help.

# #use "tree.ml";;
type 'a tree = Leaf | Node of 'a tree * 'a * 'a tree
val insert : 'a -> 'a tree -> 'a tree = <fun>
val to_list : 'a tree -> 'a list = <fun>
val size : 'a tree -> int = <fun>
val height : 'a tree -> int = <fun>
# let t = List.fold_left (fun t x -> insert x t) Leaf [5; 3; 8; 1];;
val t : int tree =
  Node (Node (Node (Leaf, 1, Leaf), 3, Leaf), 5, Node (Leaf, 8, Leaf))
# to_list t;;
- : int list = [1; 3; 5; 8]
# (size t, height t);;
- : int * int = (4, 3)
# let sorted = List.fold_left (fun t x -> insert x t) Leaf [1; 2; 3; 4; 5];;
val sorted : int tree =
  Node (Leaf, 1,
   Node (Leaf, 2, Node (Leaf, 3, Node (Leaf, 4, Node (Leaf, 5, Leaf)))))
# (size sorted, height sorted);;
- : int * int = (5, 5)

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 tree_session.py

The toplevel printed the tree as nested constructors, Node (Node (Node (Leaf, 1, Leaf), 3, Leaf), 5, Node (Leaf, 8, Leaf)), with 5 at the root. to_list read it in order, [1; 3; 5; 8], and (size t, height t) was (4, 3). Inserting [1; 2; 3; 4; 5] in sorted order gave a tree of height 5 for 5 values: each node has only a right child, so the tree is a list in disguise and a search walks every node. Balanced trees, as in the standard library’s Set and Map, exist to prevent that.

Constructors read like the type

The printed value is the declaration filled in: Node (left, value, right) everywhere a Node appears. Reading a value this way is the quickest check that a function built the shape you meant.

Recursive functions follow the shape of their type

The functions on trees share a pattern: one case per constructor, and a recursive call wherever the constructor holds a value of the type itself. size returns 0 for Leaf and size l + 1 + size r for a Node; height does the same with max. An expression tree: A tree that represents a formula, with numbers at the leaves and operators such as Add or Mul at the inner nodes, so that evaluating it is a recursive walk. shows the pattern again, with arithmetic: Num holds a number, and Add and Mul hold two sub-expressions each. Step through eval on Add (Num 2, Mul (Num 3, Num 4)):

Interactive · step by step eval on Add (Num 2, Mul (Num 3, Num 4)) Step through the calls. Each box is a constructor of the tree; its result appears beside it when its call returns.
eval on Add (Num 2, Mul (Num 3, Num 4)), step 6 of 6. Showing Add (returns 14), Num 2 (returns 2), Mul (returns 12), Num 3 (returns 3), Num 4 (returns 4). In focus: Add.Addreturns 14Num 2returns 2Mulreturns 12Num 3returns 3Num 4returns 4

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. The whole tree. The root is Add with two sub-expressions, Num 2 and a Mul. eval e starts here, in the Add case, which needs eval of both parts.
  2. A number answers at once. eval (Num 2) is the Num case, which has no sub-expression, so it returns 2 directly.
  3. Mul needs its own parts. eval of the Mul is the Mul case. It calls eval on Num 3 and on Num 4, one recursive call for each sub-expression in the constructor.
  4. Two more numbers. Num 3 returns 3 and Num 4 returns 4, both from the Num case.
  5. Mul returns. The Mul case multiplies what its two calls returned, 3 * 4, and returns 12.
  6. Add returns. The Add case adds 2 and 12 and returns 14, the value the session printed for eval e. Every constructor was visited once, by the case written for it.

eval and show on two expression trees Python · expr_session.py
from session import toplevel, write

# An expression tree: a syntax tree for arithmetic. eval and show follow the type, one case per constructor and one
# recursive call per sub-expression.
write("expr.ml", """type expr = Num of int | Add of expr * expr | Mul of expr * expr

let rec eval = function
  | Num n -> n
  | Add (a, b) -> eval a + eval b
  | Mul (a, b) -> eval a * eval b

let rec show = function
  | Num n -> string_of_int n
  | Add (a, b) -> "(" ^ show a ^ " + " ^ show b ^ ")"
  | Mul (a, b) -> show a ^ " * " ^ show b
""")
toplevel("""
#use "expr.ml";;
let e = Add (Num 2, Mul (Num 3, Num 4));;
(show e, eval e);;
let f = Mul (Add (Num 2, Num 3), Num 4);;
(show f, eval f);;
""")

Output

$ ocaml
OCaml version 5.5.1
Enter #help;; for help.

# #use "expr.ml";;
type expr = Num of int | Add of expr * expr | Mul of expr * expr
val eval : expr -> int = <fun>
val show : expr -> string = <fun>
# let e = Add (Num 2, Mul (Num 3, Num 4));;
val e : expr = Add (Num 2, Mul (Num 3, Num 4))
# (show e, eval e);;
- : string * int = ("(2 + 3 * 4)", 14)
# let f = Mul (Add (Num 2, Num 3), Num 4);;
val f : expr = Mul (Add (Num 2, Num 3), Num 4)
# (show f, eval f);;
- : string * int = ("(2 + 3) * 4", 20)

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 expr_session.py

eval e gave 14 and show e printed (2 + 3 * 4); the second tree, Mul (Add (Num 2, Num 3), Num 4), printed as (2 + 3) * 4 and gave 20. The shape of the data decided the order of the work: Mul sits above Add in the second tree, so the addition happens first. Because each function has a case for every constructor, adding a new one, say Sub, makes the compiler point to every function that does not handle it yet, through warning 8.

Constructor in the type Case in the function
Leaf, Num n: no sub-value of the type a direct answer
Node (l, v, r): two sub-trees a call on l and on r, combined with v
Add (a, b), Mul (a, b) a call on a and on b, combined by the operator

Key idea

Write one case per constructor and one recursive call per field of the type itself; the function then mirrors the type, and the exhaustiveness check covers every case.

Checkpoint

Check: Recursive, parameterised types · Functions that follow the type

  1. Question 1 of 2 With the lesson's insert, what is the height of the tree built from [1; 2; 3; 4; 5; 6; 7] in that order?

    Type a number.

    Show the answer: Question 1 of 2

    Answer: 7

    Each value is larger than every value before it, so each goes to the right of the last one: a chain of 7 nodes. The same values in the order [4; 2; 6; 1; 3; 5; 7] give a height of 3.

  2. Question 2 of 2 A constructor Sub of expr * expr is added to expr, and eval is left as it was. What happens?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: eval compiles with warning 8, which gives Sub (_, _) as a case that is not matched

    This is the payoff of writing one case per constructor: the compiler lists every function a new case leaves out, as the toplevel did with "Here is an example of a case that is not matched: Sub (_, _)".

Practise: variants, options and trees

The questions use the session’s shapes, options, trees and expressions with new values. Work out each result before you check:

Practice that adapts to you

Practise this lesson

11 questions about 4 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 11 Which of these can be a constructor of a variant type?

    Choose one answer.

    Show the answer: Question 1 of 11

    Answer: Circle

    Circle, Rect and Dot in the session are constructors; area and name are functions.

  2. Question 2 of 11 The incomplete name from the lesson, which handles Red and Green only, is called with Blue. What happens at run time?

    Choose one answer.

    Show the answer: Question 2 of 11

    Answer: It raises the exception Match_failure

    Treat warning 8 as an error to fix: dune's development profile already turns many warnings into errors.

  3. Question 3 of 11 type level = High | Low | Custom of int. What does compare (Custom 0) Low return?

    Type a number.

    Show the answer: Question 3 of 11

    Answer: 1

    The built-in compare puts constructors without arguments before those with arguments, whatever the declaration says, so Custom 0 is greater than Low and compare returns 1. Write a comparison of your own when the order matters.

  4. Question 4 of 11 What is the type of List.nth_opt [10; 20] 1?

    Choose one answer.

    Show the answer: Question 4 of 11

    Answer: int option

    The toplevel printed - : int option = Some 20 for position 1 and None for position 5.

  5. Question 5 of 11 What does Option.value ~default:(-1) (List.nth_opt [4; 5] 9) give?

    Type a number.

    Show the answer: Question 5 of 11

    Answer: -1

    Position 9 does not exist, so nth_opt gives None and Option.value returns the default, -1.

  6. Question 6 of 11 A function looks up a user by name, and a missing user is a normal outcome that every caller must handle. What should it return?

    Choose one answer.

    Show the answer: Question 6 of 11

    Answer: A user option, so the type makes every caller handle None

    The standard library offers both styles, List.nth and List.nth_opt; for an outcome callers must expect, the option is the safer interface.

  7. Question 7 of 11 What does the 'a in type 'a tree = Leaf | Node of 'a tree * 'a * 'a tree mean?

    Choose one answer.

    Show the answer: Question 7 of 11

    Answer: A type parameter: the same definition gives int tree, string tree and so on

    The session's t had the type int tree, built with the same insert that works for any ordered type.

  8. Question 8 of 11 What does to_list return for the tree built by inserting [4; 2; 6] in that order?

    Choose one answer.

    Show the answer: Question 8 of 11

    Answer: [2; 4; 6]

    The session's to_list gave [1; 3; 5; 8] for [5; 3; 8; 1] for the same reason.

  9. Question 9 of 11 How many cases does size need for the type 'a tree = Leaf | Node of 'a tree * 'a * 'a tree?

    Choose one answer.

    Show the answer: Question 9 of 11

    Answer: Two, one per constructor

    One case per constructor, and in the Node case one call per sub-tree: size l + 1 + size r.

  10. Question 10 of 11 What does eval (Mul (Num 5, Add (Num 1, Num 2))) give?

    Type a number.

    Show the answer: Question 10 of 11

    Answer: 15

    The Add is evaluated first because it is inside the Mul: 1 + 2 = 3, then 5 * 3 = 15.

  11. Question 11 of 11 The lesson's show prints brackets only around Add. Why does Mul (Add (Num 2, Num 3), Num 4) print as (2 + 3) * 4 and still read correctly?

    Choose one answer.

    Show the answer: Question 11 of 11

    Answer: The Add case adds its own brackets, so the sum is grouped wherever it appears

    The session printed ("(2 + 3) * 4", 20). The shape of the tree, not the text, decides what is computed.

Interview questions

Warm-up (fresher to 2–5 years): what is option in OCaml, and why is it used instead of null?

option is a variant type from the standard library, type 'a option = None | Some of 'a. A function that may have no result returns None in that case and Some value otherwise, as List.nth_opt does. Because int option is a different type from int, the caller cannot use the result as a number until it has handled both cases, with a match or helpers such as Option.value ~default. A null in other languages hides inside every value and fails at run time; an option puts the possibility of “no answer” in the type, where the compiler can check it.

Two harder questions follow, about a match that started failing after a new case was added and about a tree that became slow. Decide what you would check first, then open each first step:

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Mid to senior

    A payment status type gained a constructor Refunded. The build passed, but in production a report crashed with Match_failure on refunded payments. The report's match has no catch-all case. How did this get through, and what would you change so the next new constructor cannot?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    An in-house binary search tree stores customer ids. It was fast in tests with random ids, but in production ids arrive in increasing order and lookups take time proportional to the number of customers. Explain why, and what you would do.

    Model answer, Pro. First step and follow-ups

Flashcards · 7 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. What is a variant type?

    A type that lists every case a value can be as a constructor. Constructors may carry values, and they are not functions.

  2. What does warning 8 report, and what happens if you ignore it?

    A match that misses a case, with an example value. That value raises Match_failure at run time, as the warning predicted.

  3. What is option, and why is it used where other languages use null?

    The variant type 'a option = None | Some of 'a. It puts a missing answer in the type, so the compiler makes the caller deal with None before using the value.

  4. How can a caller use an option's value?

    With a match, or with Option.value ~default and Option.map. List.nth_opt [10; 20] 5, for example, returns None.

  5. What makes a type such as 'a tree recursive and parameterised?

    Its constructors refer to the type itself (a node holds subtrees) and 'a lets it hold values of any one type.

  6. What happens when a search tree is built from sorted input?

    It ends up as deep as a list, with one node on each level.

  7. How is a function over a recursive type best written?

    One case per constructor and one recursive call per sub-value of the type itself; the exhaustiveness check then points at any case a new constructor leaves out.

Key takeaways

  • A variant type lists every case as a constructor; constructors may carry values, are not functions, and a match that misses one draws warning 8 with an example.
  • option, None or Some v, puts a missing answer in the type, so the caller handles it with a match, Option.value or Option.map before using the value.
  • A recursive, parameterised type such as 'a tree refers to itself in its constructors, and a sorted input gives a search tree as deep as a list.
  • A function that follows its type has one case per constructor and one recursive call per sub-value of the type, so the compiler can point to any case a new constructor leaves out.

Terms in this lesson

constructor
A capitalised name such as Some or Circle that builds one case of a variant type, with or without values inside, and names that case in patterns.
expression tree
A tree that represents a formula, with numbers at the leaves and operators such as Add or Mul at the inner nodes, so that evaluating it is a recursive walk.
option
The standard variant type 'a option = None | Some of 'a, used for a result that may be missing instead of a null value.
recursive type
A type whose definition refers to itself, such as a tree whose Node constructor holds two smaller trees.
variant type
A type that lists every form its values can take, each a constructor, such as type shape = Circle of float | Dot.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.