Variable declarations in OCaml bind variables within a scope, the
part of the program where the variable stands for the value it is bound to.
For example, when we write
let x = e1
the scope of the identifier x is the expression
that scope, the identifier x stands for whatever value
v the expression e1
Since x = v, OCaml evaluates the
let expression by rewriting it to
e2, but with the value
v substituted for the occurrences of x.
For example, the expression
let x = 2 in x + 3 is
2 + 3, and then arithmetic is used to obtain
the result value
Functions also bind variables. When we write a function definition in OCaml, we introduce new variables for the function name and for function arguments. For example, in this expression two variables are bound:
let f x = e1 in e2
The scope of the formal parameter x is exactly the expression e1. The scope of the variable f (which is bound to a function value) is the body of the let, e2.
let expression can introduce multiple variables at once,
as in the following example:
let x = 2 and y = 3 in x + y
y have the body of the
as their scope. Even though
y is declared after
the definition of
y cannot refer to the variable
x—it isn't in scope.
To declare a recursive function, the function must be in scope within its
own body. In OCaml, this requires using a
let rec instead of
let rec, every variable it declares
is in scope within its own definition and within the definitions of all the
other variables. To make this work, all the definitions that use these variables
must be functions. For example, here is how we could define
mutually recursive functions
let rec even x = x = 0 || odd (x-1) and odd x = not (x = 0 || not (even (x-1))) in odd 3110
There are two variables named
x in this example, both of which
are in scope only within the respective functions that bind them. However,
odd are in scope in each
other's definitions and within the body of the
It is possible to name things defined in a module without using a
qualified identifier, using the
# String.length "hi";; - : int = 2 # open String;; # length "bye";; - : int = 3
There are a number of
pre-defined library modules provided by OCaml that are extremely useful.
For instance, the
module provides a number of useful operations
on strings, and the
module provides operations on lists. Many useful operations are
Pervasives module, which is already open by default.
To find out more about the OCaml libraries and the operations they
the Objective Caml Reference Manual, part IV.
For example, there is a built-in operation for calculating the absolute value
of an integer called
Pervasives.abs, which can be called simply
Take some time to browse through the libraries and find out what they provide. You shouldn't recode something that's available in the library (unless we ask you to do so explicitly.)
We saw that a function with multiple parameters is really just syntactic sugar for a function that is passed a tuple as an argument. For example,
let plus (x, y) = x + yis sugar for
let plus (z : int * int) = match z with (x, y) -> x + ywhich in turn is sugar for
let plus = fun (z : int * int) -> match z with (x, y) -> x + yWhen we apply this function, say to the tuple
(2, 3), evaluation proceeds as follows:
plus (2, 3) = (fun (z : int * int) -> match z with (x, y) -> x + y) (2, 3) = match (2, 3) with (x, y) -> x + y = 2 + 3 = 5
It turns out that OCaml has another way to declare functions with multiple formal arguments, and in fact it is the usual way. The above declaration can be given in curried form as follows:
let plus x y = x + y
or with all the types written explicitly:
let plus (x : int) (y : int) : int = x + y
Notice that there is no comma between the parameters. Similarly, when applying a curried function, we write no comma:
plus 2 3 = 2 + 3 = 5
There is more going on here than it might seem. Recall we said that functions
really only have one argument. When we write
plus 2 3, the
plus is only being passed one argument, the number 2.
We can parenthesize the term as
(plus 2) (3), because application
is left-associative. In other words,
plus 2 must return a function that can be applied to 3 to obtain
the result 5. In fact,
plus 2 returns a function that adds 2 to
How does this work? The curried declaration above is syntactic sugar for the creation of a higher-order function. It stands for:
let plus = function (x : int) -> function (y : int) -> x + y
plus 2 3 proceeds as follows:
plus 2 3 = ((function (x : int) -> function (y : int) -> x + y) 2) 3 = (function (y : int) -> 2 + y) 3 = 2 + 3 = 5
plus is really a function that takes in an
as an argument, and returns a new function of type
int -> int.
Therefore, the type of
int -> (int -> int).
We can write this simply as
int -> int -> int because the
-> is right-associative.
It turns out that we can view binary operators like
functions, and they are curried just like
# (+);; - : int -> int -> int = <fun> # (+) 2 3;; - : int = 5 # let next = (+) 1;; val next : int -> int = <fun> # next 7;; - : int = 8;
So far the only real data structures we can build are made of tuples. But tuples don't let us make data structures whose size is not known at compile time. For that we need a new language feature.
One simple data structure that we're used to is singly linked lists.
It turns out that OCaml
has lists built in. For example, in OCaml the expression
 is an
empty list. The expression
[1;2;3] is a list containing three
integers. Another name for the empty list is
nil. This is just the same thing as
In OCaml, all the elements of a list have to have the same type. For
example, a list of integers has the type
Similarly, the list
["hi"; "there"; "3110"] would have the type
string list. But
[1; "hi"] is not a legal
list. Lists in OCaml are homogeneous lists, as opposed to
heterogeneous lists in which each element can have a different type.
Lists are immutable: you cannot change the elements of a list, unlike an array in Java. Once a list is constructed, it never changes.
Often we want to make a list out of smaller lists. We can concatenate
two lists with the
@ operator. For example,
[1;2;3;4;5]. However, this operator
isn't very fast because it needs to build a copy of the entire first
list. (It doesn't make a copy of the second list because the storage of the
second list is shared with the storage of the concatenated list.)
More often when building up lists
we use the
:: operator, which prepends an
element to the front of an existing list (“prepend” means “append onto the front”).
1 prepended onto
[2;3]. This is just the list
If we use
:: on the empty list, it makes a one-element list:
For historical reasons going back to the language Lisp, we usually
:: operator “cons”.
The fact that lists are immutable is in keeping with OCaml being a
functional language. It is also actually useful for making OCaml more efficient,
because it means that different list data structures can share parts of their
representation in the computer's memory. For example, evaluating
only requires allocating space for a single extra list node in the computer's
memory. It shares the rest of the list with the existing list
The best way to extract elements from a list is to use pattern matching.
:: and the bracket constructor can be used as
patterns in a
match expression. For example, if we had a list
lst and wanted to
get the value 0 if
lst was empty,
lst had one element, and 2 if
2 or more elements, we could write:
match lst with  -> 0 | [x] -> 1 | _ -> 2
x would be bound to the single element of the list if
the second match arm were evaluated.
Often, functions that manipulate lists are recursive, because they need
to do something to every element. For example, suppose that we wanted to
compute the length of a list of strings. We could write a recursive function
that accomplishes this (in fact, the library function
does just this):
(* Returns the length of lst *) let rec length (lst : string list) : int = match lst with  -> 0 | h :: t -> 1 + length t
The logic here is that if a list is empty (
its length is clearly zero. Otherwise, if it is the appending of an
element h onto another list t, its length must be one greater than the
length of t.
It's possible to write patterns using the bracket syntax. This is
exactly the same as writing a similar pattern using the
operator. For example, the following patterns are all equivalent:
x::. These expressions are also all equivalent when
used as terms.
The OCaml structure
List contains many useful functions for
manipulating lists. Before using lists, it's worth taking a look.
Some of them we'll talk about later in more detail. Two functions
that should be used with caution are
These functions get the head and tail of a list, respectively. However,
they raise an exception if applied to an empty list. They make it
easy to forget about the possibility that the list might be empty, creating
expected exceptions that crash your program. So it's usually best to avoid them.
We can use pattern matching to implement other useful functions on lists. Suppose we wanted a function that would extract a list element by its index within the list, with the first element at index zero. We can implement this neatly by doing a pattern match on the list and the integer n at the same time:
(* nth lst n returns the nth element of lst. *) let rec nth (lst : string list) (n : int) : string = match lst with h :: t -> if n = 0 then h else nth t (n - 1) |  -> raise Not_found
Not_found exception is raised if
less than 0 or greater than or equal to the length of