One of the main usage of variants is to define recursive, and usually parameterized, structures.
Custom lists
Lists are a first example. We can define our own list structure with textual constructors:
type 'a mylist = Empty | Cell of 'a * 'a mylist
(Note that these constructors are completely distinct from the builtin list type.)The type mylist is recursive: a cell contains a
mylist which represents the tail (the following cells). Here is an example:
Cell( 10, Cell(20, Empty) )
- Write a function myhd with type 'a mylist → 'a which returns the first element of a list, or fails with
failwith "empty list"
.
No if, only pattern-matching. - Similarly, define mytl with type 'a mylist → 'a mylist which returns the tail of a list, or fails.
- By the way, can you guess the type of
failwith "foo"
? Trying failwith "foo" ;; does not give its type, but you have other ways to find it. - Define mylength with type 'a mylist → int which returns the length of a list. Do not use mytl or myhd, use only pattern-matching.
- Define the tail-recursive version of mylength, using an accumulator. Its type is int → α mylist → int.
- In order to define the tail-recursive version of mylength while keeping the original type α mylist → int, we proceed as follows:
let mylength l =
let rec loop acu l =
...
in
loop 0 l
Builtin lists
The builtin list type is defined like this:
type 'a list = [] | (::) of 'a * 'a list
(Do not redefine it)
::
is a prefix constructor, so you write a :: b instead of :: (a,b)
It works also in pattern-matching (which you already know):
let f = function
| [] -> "empty list"
| a :: _ -> "list starting with " ^ a
(As usual, try to guess the type of f)
Option type
The following type is already defined in OCaml: type 'a option = None | Some of 'a
It can be used to return a result (Some x), or nothing (None) when nothing can be returned.
Exercise : Option type
- Write a function ohd ("optional head") of type 'a list → 'a option which returns
Some x if the list head is x, and returns None if the list is empty.
Use only pattern-matching. No if, no other functions. - Similarly for otl ("optional tail").