Skip to content

Sharif's Page

Data Types in OCaml

When we make our programs more and more complex, we need more complex data types as well. We have only used OCaml's built-in data types, how can we construct our own data types?

type

The type keyword is similar to the typedef keyword in C, except more limited in scope. A type can only be multiple variants of arbitrary values.

(* coin is enum with variants Heads and Tails*)
type coin = Heads | Tails

Each variant can also contain data of other data types.

type shape =
 | Rect of float * float
 | Circle of float
let r = Rect (3.0, 4.0) (* r has type shape *)

shape here has two variants. It can either be a tuple of two floats when it is a Rect, or it can be a single float when it is a Circle.

These data types are also known as algebraic data types or tagged unions.

Option

ADTs can be useful when we want to ensure the complete handling of all cases. For example, if an object is nullable, it is useful to make sure that we must handle the null case instead of passing that off to the developer who might carelessly not handle it. This is where the option type comes from.

type 'a option =
 | Some of 'a
 | None

The 'a keyword means that that the type option is polymorphic, and the variant Some will contain whatever type that option is defined for. When handling an option, you must destructure it into its Some and None variants and handle both cases, otherwise OCaml will warn you for a non-exhaustive pattern match.

List

We can actually define our own list data type as a recursive data type, which is a data type which contains itself.

type 'a list =
 | Nil
 | Cons of 'a * 'a list

Here, list has two variants, Nil and a Cons tuple of an element and a list. If we think of the traditional list data type, this is actually just a more verbose version. [] is sugar for Nil and :: is sugar for Cons tuple.

let rec len l =
    match l with
    | Nil -> 0
    | Cons (_, t) -> 1 + (len t)
(* same as *)
let rec len l =
    match l with
    | [] -> 0
    | _ :: t -> 1 + (len t)

Exceptions

Exceptions are a special data type used for errors in OCaml. Exceptions are similar to type constructors in that they can take arguments or have none.

exception Sign of int
let f n =
    if n > 0 then
        raise (Sign n)
    else
        raise (Failure "foo")

We can raise an exception with arguments whenever we want, which will exit the function with the exception name and its arguments. Failure is a generic exception type that is used with strings.

There is also special try syntax used to catch exceptions.

let g n =
    try
        f n
    with Sign n ->
            Printf.printf "Caught %d\n" n
          | Failure s ->
            Printf.printf "Caught %s\n" s

The function g will try running f n, but if that raises an exception, it will be caught in with. It can be pattern matched for different exception types.