The Objective Caml system
release 3.09
Documentation and user's manual
Xavier Leroy
(with Damien Doligez, Jacques Garrigue, Didier Rémy and Jérôme Vouillon)

  Copyright © 2005 Institut National de Recherche en Informatique et en Automatique



This manual is also available in PDF. Postscript, DVI, plain text, as a bundle of HTML files, and as a bundle of Emacs Info files.

Contents

Foreword

This manual documents the release 3.09 of the Objective Caml system. It is organized as follows.

Conventions

Objective Caml runs on several operating systems. The parts of this manual that are specific to one operating system are presented as shown below:

  Unix:
This is material specific to the Unix family of operating systems, including Linux and MacOS X.
  Windows:
This is material specific to Microsoft Windows (95, 98, ME, NT, 2000, XP).

License

The Objective Caml system is copyright © 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Institut National de Recherche en Informatique et en Automatique (INRIA). INRIA holds all ownership rights to the Objective Caml system.

The Objective Caml system is open source and can be freely redistributed. See the file LICENSE in the distribution for licensing information.

The present documentation is copyright © 2005 Institut National de Recherche en Informatique et en Automatique (INRIA). The Objective Caml documentation and user's manual may be reproduced and distributed in whole or in part, subject to the following conditions:

Availability

The complete Objective Caml distribution can be accessed via the http://caml.inria.fr/Caml Web site. The http://caml.inria.fr/Caml Web site contains a lot of additional information on Objective Caml.

Part I
An introduction to Objective Caml


Chapter 1  The core language

This part of the manual is a tutorial introduction to the Objective Caml language. A good familiarity with programming in a conventional languages (say, Pascal or C) is assumed, but no prior exposure to functional languages is required. The present chapter introduces the core language. Chapter 3 deals with the object-oriented features, and chapter 2 with the module system.

1.1  Basics

For this overview of Caml, we use the interactive system, which is started by running ocaml from the Unix shell, or by launching the OCamlwin.exe application under Windows. This tutorial is presented as the transcript of a session with the interactive system: lines starting with # represent user input; the system responses are printed below, without a leading #.

Under the interactive system, the user types Caml phrases, terminated by ;;, in response to the # prompt, and the system compiles them on the fly, executes them, and prints the outcome of evaluation. Phrases are either simple expressions, or let definitions of identifiers (either values or functions).
#1+2*3;;
- : int = 7
 
#let pi = 4.0 *. atan 1.0;;
val pi : float = 3.14159265358979312
 
#let square x = x *. x;;
val square : float -> float = <fun>
 
#square(sin pi) +. square(cos pi);;
- : float = 1.
The Caml system computes both the value and the type for each phrase. Even function parameters need no explicit type declaration: the system infers their types from their usage in the function. Notice also that integers and floating-point numbers are distinct types, with distinct operators: + and * operate on integers, but +. and *. operate on floats.
#1.0 * 2;;
This expression has type float but is here used with type int
Recursive functions are defined with the let rec binding:
#let rec fib n =
   if n < 2 then 1 else fib(n-1) + fib(n-2);;
val fib : int -> int = <fun>
 
#fib 10;;
- : int = 89

1.2  Data types

In addition to integers and floating-point numbers, Caml offers the usual basic data types: booleans, characters, and character strings.
#(1 < 2) = false;;
- : bool = false
 
#'a';;
- : char = 'a'
 
#"Hello world";;
- : string = "Hello world"
Predefined data structures include tuples, arrays, and lists. General mechanisms for defining your own data structures are also provided. They will be covered in more details later; for now, we concentrate on lists. Lists are either given in extension as a bracketed list of semicolon-separated elements, or built from the empty list [] (pronounce “nil”) by adding elements in front using the :: (“cons”) operator.
#let l = ["is"; "a"; "tale"; "told"; "etc."];;
val l : string list = ["is"; "a"; "tale"; "told"; "etc."]
 
#"Life" :: l;;
- : string list = ["Life"; "is"; "a"; "tale"; "told"; "etc."]
As with all other Caml data structures, lists do not need to be explicitly allocated and deallocated from memory: all memory management is entirely automatic in Caml. Similarly, there is no explicit handling of pointers: the Caml compiler silently introduces pointers where necessary.

As with most Caml data structures, inspecting and destructuring lists is performed by pattern-matching. List patterns have the exact same shape as list expressions, with identifier representing unspecified parts of the list. As an example, here is insertion sort on a list:
#let rec sort lst =
   match lst with
     [] -> []
   | head :: tail -> insert head (sort tail)
 and insert elt lst =
   match lst with
     [] -> [elt]
   | head :: tail -> if elt <= head then elt :: lst else head :: insert elt tail
 ;;
val sort : 'a list -> 'a list = <fun>
val insert : 'a -> 'a list -> 'a list = <fun>
 
#sort l;;
- : string list = ["a"; "etc."; "is"; "tale"; "told"]
The type inferred for sort, 'a list -> 'a list, means that sort can actually apply to lists of any type, and returns a list of the same type. The type 'a is a type variable, and stands for any given type. The reason why sort can apply to lists of any type is that the comparisons (=, <=, etc.) are polymorphic in Caml: they operate between any two values of the same type. This makes sort itself polymorphic over all list types.
#sort [6;2;5;3];;
- : int list = [2; 3; 5; 6]
 
#sort [3.14; 2.718];;
- : float list = [2.718; 3.14]
The sort function above does not modify its input list: it builds and returns a new list containing the same elements as the input list, in ascending order. There is actually no way in Caml to modify in-place a list once it is built: we say that lists are immutable data structures. Most Caml data structures are immutable, but a few (most notably arrays) are mutable, meaning that they can be modified in-place at any time.

1.3  Functions as values

Caml is a functional language: functions in the full mathematical sense are supported and can be passed around freely just as any other piece of data. For instance, here is a deriv function that takes any float function as argument and returns an approximation of its derivative function:
#let deriv f dx = function x -> (f(x +. dx) -. f(x)) /. dx;;
val deriv : (float -> float) -> float -> float -> float = <fun>
 
#let sin' = deriv sin 1e-6;;
val sin' : float -> float = <fun>
 
#sin' pi;;
- : float = -1.00000000013961143
Even function composition is definable:
#let compose f g = function x -> f(g(x));;
val compose : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun>
 
#let cos2 = compose square cos;;
val cos2 : float -> float = <fun>
Functions that take other functions as arguments are called “functionals”, or “higher-order functions”. Functionals are especially useful to provide iterators or similar generic operations over a data structure. For instance, the standard Caml library provides a List.map functional that applies a given function to each element of a list, and returns the list of the results:
#List.map (function n -> n * 2 + 1) [0;1;2;3;4];;
- : int list = [1; 3; 5; 7; 9]
This functional, along with a number of other list and array functionals, is predefined because it is often useful, but there is nothing magic with it: it can easily be defined as follows.
#let rec map f l =
   match l with
     [] -> []
   | hd :: tl -> f hd :: map f tl;;
val map : ('a -> 'b) -> 'a list -> 'b list = <fun>

1.4  Records and variants

User-defined data structures include records and variants. Both are defined with the type declaration. Here, we declare a record type to represent rational numbers.
#type ratio = {num: int; denum: int};;
type ratio = { num : int; denum : int; }
 
#let add_ratio r1 r2 =
   {num = r1.num * r2.denum + r2.num * r1.denum;
    denum = r1.denum * r2.denum};;
val add_ratio : ratio -> ratio -> ratio = <fun>
 
#add_ratio {num=1; denum=3} {num=2; denum=5};;
- : ratio = {num = 11; denum = 15}
The declaration of a variant type lists all possible shapes for values of that type. Each case is identified by a name, called a constructor, which serves both for constructing values of the variant type and inspecting them by pattern-matching. Constructor names are capitalized to distinguish them from variable names (which must start with a lowercase letter). For instance, here is a variant type for doing mixed arithmetic (integers and floats):
#type number = Int of int | Float of float | Error;;
type number = Int of int | Float of float | Error
This declaration expresses that a value of type number is either an integer, a floating-point number, or the constant Error representing the result of an invalid operation (e.g. a division by zero).

Enumerated types are a special case of variant types, where all alternatives are constants:
#type sign = Positive | Negative;;
type sign = Positive | Negative
 
#let sign_int n = if n >= 0 then Positive else Negative;;
val sign_int : int -> sign = <fun>
To define arithmetic operations for the number type, we use pattern-matching on the two numbers involved:
#let add_num n1 n2 =
   match (n1, n2) with
     (Int i1, Int i2) ->
       (* Check for overflow of integer addition *)
       if sign_int i1 = sign_int i2 && sign_int(i1 + i2) <> sign_int i1
       then Float(float i1 +. float i2)
       else Int(i1 + i2)
   | (Int i1, Float f2) -> Float(float i1 +. f2)
   | (Float f1, Int i2) -> Float(f1 +. float i2)
   | (Float f1, Float f2) -> Float(f1 +. f2)
   | (Error, _) -> Error
   | (_, Error) -> Error;;
val add_num : number -> number -> number = <fun>
 
#add_num (Int 123) (Float 3.14159);;
- : number = Float 126.14159
The most common usage of variant types is to describe recursive data structures. Consider for example the type of binary trees:
#type 'a btree = Empty | Node of 'a * 'a btree * 'a btree;;
type 'a btree = Empty | Node of 'a * 'a btree * 'a btree
This definition reads as follow: a binary tree containing values of type 'a (an arbitrary type) is either empty, or is a node containing one value of type 'a and two subtrees containing also values of type 'a, that is, two 'a btree.

Operations on binary trees are naturally expressed as recursive functions following the same structure as the type definition itself. For instance, here are functions performing lookup and insertion in ordered binary trees (elements increase from left to right):
#let rec member x btree =
   match btree with
     Empty -> false
   | Node(y, left, right) ->
       if x = y then true else
       if x < y then member x left else member x right;;
val member : 'a -> 'a btree -> bool = <fun>
 
#let rec insert x btree =
   match btree with
     Empty -> Node(x, Empty, Empty)
   | Node(y, left, right) ->
       if x <= y then Node(y, insert x left, right)
                 else Node(y, left, insert x right);;
val insert : 'a -> 'a btree -> 'a btree = <fun>

1.5  Imperative features

Though all examples so far were written in purely applicative style, Caml is also equipped with full imperative features. This includes the usual while and for loops, as well as mutable data structures such as arrays. Arrays are either given in extension between [| and |] brackets, or allocated and initialized with the Array.create function, then filled up later by assignments. For instance, the function below sums two vectors (represented as float arrays) componentwise.
#let add_vect v1 v2 =
   let len = min (Array.length v1) (Array.length v2) in
   let res = Array.create len 0.0 in
   for i = 0 to len - 1 do
     res.(i) <- v1.(i) +. v2.(i)
   done;
   res;;
val add_vect : float array -> float array -> float array = <fun>
 
#add_vect [| 1.0; 2.0 |] [| 3.0; 4.0 |];;
- : float array = [|4.; 6.|]
Record fields can also be modified by assignment, provided they are declared mutable in the definition of the record type:
#type mutable_point = { mutable x: float; mutable y: float };;
type mutable_point = { mutable x : float; mutable y : float; }
 
#let translate p dx dy =
   p.x <- p.x +. dx; p.y <- p.y +. dy;;
val translate : mutable_point -> float -> float -> unit = <fun>
 
#let mypoint = { x = 0.0; y = 0.0 };;
val mypoint : mutable_point = {x = 0.; y = 0.}
 
#translate mypoint 1.0 2.0;;
- : unit = ()
 
#mypoint;;
- : mutable_point = {x = 1.; y = 2.}
Caml has no built-in notion of variable – identifiers whose current value can be changed by assignment. (The let binding is not an assignment, it introduces a new identifier with a new scope.) However, the standard library provides references, which are mutable indirection cells (or one-element arrays), with operators ! to fetch the current contents of the reference and := to assign the contents. Variables can then be emulated by let-binding a reference. For instance, here is an in-place insertion sort over arrays:
#let insertion_sort a =
   for i = 1 to Array.length a - 1 do
     let val_i = a.(i) in
     let j = ref i in
     while !j > 0 && val_i < a.(!j - 1) do
       a.(!j) <- a.(!j - 1);
       j := !j - 1
     done;
     a.(!j) <- val_i
   done;;
val insertion_sort : 'a array -> unit = <fun>
References are also useful to write functions that maintain a current state between two calls to the function. For instance, the following pseudo-random number generator keeps the last returned number in a reference:
#let current_rand = ref 0;;
val current_rand : int ref = {contents = 0}
 
#let random () =
   current_rand := !current_rand * 25713 + 1345;
   !current_rand;;
val random : unit -> int = <fun>
Again, there is nothing magic with references: they are implemented as a one-field mutable record, as follows.
#type 'a ref = { mutable contents: 'a };;
type 'a ref = { mutable contents : 'a; }
 
#let (!) r = r.contents;;
val ( ! ) : 'a ref -> 'a = <fun>
 
#let (:=) r newval = r.contents <- newval;;
val ( := ) : 'a ref -> 'a -> unit = <fun>
In some special cases, you may need to store a polymorphic function in a data structure, keeping its polymorphism. Without user-provided type annotations, this is not allowed, as polymorphism is only introduced on a global level. However, you can give explicitly polymorphic types to record fields.
#type idref = { mutable id: 'a. 'a -> 'a };;
type idref = { mutable id : 'a. 'a -> 'a; }
 
#let r = {id = fun x -> x};;
val r : idref = {id = <fun>}
 
#let g s = (s.id 1, s.id true);;
val g : idref -> int * bool = <fun>
 
#r.id <- (fun x -> print_string "called id\n"; x);;
- : unit = ()
 
#g r;;
called id
called id
- : int * bool = (1,