Est. 1996 Intermediate

OCaml

A powerful functional programming language combining static typing, type inference, and a sophisticated module system - used at Jane Street, Meta, and in formal verification.

Created by Xavier Leroy, Jérôme Vouillon, Damien Doligez, Didier Rémy (INRIA)

Paradigm Multi-paradigm: Functional, Imperative, Object-Oriented
Typing Static, Strong, Inferred
First Appeared 1996
Latest Version OCaml 5.2 (2024)

OCaml is a general-purpose, industrial-strength programming language that combines functional, imperative, and object-oriented programming in a statically-typed language with type inference. It occupies a unique “sweet spot” in language design - expressive enough for complex software yet practical enough for real-world production systems.

History & Origins

OCaml’s story begins with ML (Meta Language), created by Robin Milner in 1972 at Stanford for the LCF proof assistant. ML introduced revolutionary concepts: type inference, pattern matching, and algebraic data types - features that would influence decades of language design.

From Caml to OCaml

In 1987, the Formel project at INRIA (the French national research institute) created Caml, the first implementation of the ML dialect that would evolve into OCaml. The journey continued:

Caml Light (1990) - Xavier Leroy and Damien Doligez created a lightweight, portable implementation with a bytecode compiler and fast garbage collector. This made ML-family languages practical for everyday use.

Caml Special Light (1995) - Added a native code compiler, dramatically improving performance. Programs could now compete with C in execution speed while maintaining type safety.

Objective Caml (1996) - Didier Rémy and Jérôme Vouillon added a powerful object system, enabling object-oriented programming with full static type safety. The name was later shortened to “OCaml” in 2011.

Modern OCaml

OCaml 5.0 (2022) marked a major milestone with multicore support and effect handlers, enabling efficient parallel programming while maintaining the language’s signature safety guarantees.

What Makes OCaml Different

1. Type Inference Without Annotations

OCaml’s Hindley-Milner type system can infer types for entire programs without explicit annotations:

1
2
3
4
5
6
7
8
(* The compiler knows this is int -> int -> int *)
let add x y = x + y

(* And this is string -> string -> string *)
let greet name greeting = greeting ^ ", " ^ name ^ "!"

(* Type errors are caught at compile time *)
(* let broken = add "hello" 5  -- Won't compile! *)

2. Algebraic Data Types and Pattern Matching

Define complex data structures and destructure them elegantly:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
(* Define a binary tree *)
type 'a tree =
  | Empty
  | Node of 'a * 'a tree * 'a tree

(* Pattern match to process it *)
let rec sum_tree = function
  | Empty -> 0
  | Node (value, left, right) ->
      value + sum_tree left + sum_tree right

(* The compiler warns about missing cases! *)

3. Powerful Module System

OCaml’s module system enables sophisticated abstraction and code organization:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
(* Define a module signature (interface) *)
module type STACK = sig
  type 'a t
  val empty : 'a t
  val push : 'a -> 'a t -> 'a t
  val pop : 'a t -> ('a * 'a t) option
end

(* Implement it - internals are hidden *)
module ListStack : STACK = struct
  type 'a t = 'a list
  let empty = []
  let push x s = x :: s
  let pop = function
    | [] -> None
    | x :: xs -> Some (x, xs)
end

Functors (modules parameterized by modules) enable powerful generic programming:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
(* A functor that adds logging to any module *)
module MakeLogged (S : STACK) : STACK = struct
  type 'a t = 'a S.t
  let empty = S.empty
  let push x s =
    print_endline "Pushing element";
    S.push x s
  let pop s =
    print_endline "Popping element";
    S.pop s
end

4. First-Class Functions and Closures

Functions are values that can be passed around, returned, and composed:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
(* Function returning a function *)
let make_multiplier n = fun x -> x * n

let double = make_multiplier 2
let triple = make_multiplier 3

(* Compose functions *)
let (>>) f g x = g (f x)
let sextuple = double >> triple

(* Higher-order functions *)
let apply_twice f x = f (f x)
let quadruple = apply_twice double

5. Imperative Features When Needed

Unlike purely functional languages, OCaml pragmatically supports mutation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
(* Mutable references *)
let counter = ref 0
let increment () =
  counter := !counter + 1;
  !counter

(* Mutable arrays *)
let arr = [| 1; 2; 3 |]
let () = arr.(0) <- 10

(* While loops *)
let factorial n =
  let result = ref 1 in
  let i = ref n in
  while !i > 1 do
    result := !result * !i;
    decr i
  done;
  !result

6. Object-Oriented Programming

Full object-oriented features with structural typing:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
(* Define a class *)
class point x_init y_init = object
  val mutable x = x_init
  val mutable y = y_init
  method get_x = x
  method get_y = y
  method move dx dy = x <- x + dx; y <- y + dy
end

(* Create and use objects *)
let p = new point 0 0
let () = p#move 3 4
let distance = sqrt (float (p#get_x * p#get_x + p#get_y * p#get_y))

Why OCaml?

Performance

OCaml’s native code compiler produces executables that rival C in speed:

  • No runtime type checks (types are erased after compilation)
  • Efficient unboxed representations for numeric types
  • Generational garbage collector with very low pause times
  • Whole-program optimization through cross-module inlining

Safety

The type system catches errors before they become bugs:

  • No null pointer exceptions (use option types)
  • Exhaustive pattern matching (compiler warns about missing cases)
  • Immutability by default (mutation is explicit)
  • Strong encapsulation through module signatures

Expressiveness

Complex ideas map directly to code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
(* Express a JSON structure directly *)
type json =
  | Null
  | Bool of bool
  | Int of int
  | Float of float
  | String of string
  | Array of json list
  | Object of (string * json) list

(* Parse and pretty-print naturally *)
let rec to_string = function
  | Null -> "null"
  | Bool b -> string_of_bool b
  | Int i -> string_of_int i
  | Float f -> string_of_float f
  | String s -> "\"" ^ String.escaped s ^ "\""
  | Array items ->
      "[" ^ String.concat ", " (List.map to_string items) ^ "]"
  | Object fields ->
      let field_to_string (k, v) = "\"" ^ k ^ "\": " ^ to_string v in
      "{" ^ String.concat ", " (List.map field_to_string fields) ^ "}"

The OCaml Ecosystem

Build Tools

  • opam - Package manager with dependency resolution and version constraints
  • dune - Modern build system with declarative configuration
  • utop - Enhanced REPL with auto-completion
  • Core / Base - Jane Street’s standard library alternatives
  • Lwt / Async - Cooperative threading/concurrency
  • Cohttp - HTTP client/server library
  • Yojson - JSON parsing and generation
  • Dream - Web framework
  • Js_of_ocaml - Compile OCaml to JavaScript
  • Eio - Modern effect-based I/O (OCaml 5+)

Development Tools

  • Merlin - Editor integration for code completion and type information
  • ocamlformat - Automatic code formatting
  • odoc - Documentation generator
  • LSP - Language Server Protocol support

Getting Started

OCaml files use the .ml extension (with .mli for interface files). A basic structure:

1
2
3
4
5
6
7
8
9
(* hello.ml *)

(* Define a function *)
let greet name =
  Printf.printf "Hello, %s!\n" name

(* Entry point - expressions at module level are executed *)
let () =
  greet "World"

The REPL

OCaml has an excellent interactive environment:

$ ocaml
        OCaml version 5.2.0

# 1 + 2;;
- : int = 3
# let double x = x * 2;;
val double : int -> int = <fun>
# double 21;;
- : int = 42
# List.map double [1; 2; 3; 4];;
- : int list = [2; 4; 6; 8]

Note: Lines must end with ;; in the REPL (but not in source files).

Compilation

1
2
3
4
5
6
7
8
# Bytecode (portable, faster compilation)
ocamlc hello.ml -o hello

# Native code (faster execution)
ocamlopt hello.ml -o hello

# Run directly (interpreted)
ocaml hello.ml

A Complete Example

Here’s a more complete OCaml program demonstrating various features:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
(* Simple command-line word counter *)

(* Define a record type *)
type stats = {
  lines: int;
  words: int;
  chars: int;
}

(* Create an empty stats record *)
let empty_stats = { lines = 0; words = 0; chars = 0 }

(* Count words in a line *)
let count_words line =
  line
  |> String.split_on_char ' '
  |> List.filter (fun s -> String.length s > 0)
  |> List.length

(* Process a single line *)
let process_line stats line =
  {
    lines = stats.lines + 1;
    words = stats.words + count_words line;
    chars = stats.chars + String.length line + 1;  (* +1 for newline *)
  }

(* Read all lines from a channel *)
let rec read_all_lines channel acc =
  match input_line channel with
  | line -> read_all_lines channel (line :: acc)
  | exception End_of_file -> List.rev acc

(* Main function *)
let () =
  let lines = read_all_lines stdin [] in
  let stats = List.fold_left process_line empty_stats lines in
  Printf.printf "%d lines, %d words, %d chars\n"
    stats.lines stats.words stats.chars

The OCaml Community

Resources

  • ocaml.org - Official site with documentation and tutorials
  • Real World OCaml - Free online book (realworldocaml.org)
  • OCaml Manual - Comprehensive language reference
  • OCamlverse - Community wiki

Learning Path

  1. OCaml from the Very Beginning - Beginner-friendly introduction
  2. Real World OCaml - Practical, comprehensive guide
  3. More OCaml - Advanced algorithms and techniques
  4. Types and Programming Languages - Theoretical foundations

Community

  • OCaml Discuss forum
  • r/ocaml subreddit
  • OCaml Discord
  • Functional Programming Slack (#ocaml)

OCaml vs Similar Languages

FeatureOCamlHaskellF#Rust
EvaluationStrictLazyStrictStrict
MutabilityOpt-inOpt-inOpt-inOpt-in
OOPYesNoYesNo
Module SystemSophisticatedType classes.NET basedTraits
GCYesYesYesNo
MulticoreYes (5.0+)YesYesYes

Continue to the Hello World tutorial to write your first OCaml program.

Timeline

1972
Robin Milner releases ML as the meta-language for the LCF proof assistant
1987
First Caml implementation by Ascánder Suárez at INRIA
1990
Caml Light released by Xavier Leroy and Damien Doligez with bytecode compiler
1995
Caml Special Light adds native code compiler with significant performance gains
1996
Objective Caml (OCaml) released with object-oriented features by Rémy and Vouillon
2000
Jacques Garrigue adds polymorphic methods, variants, and labeled arguments
2012
OCaml 4.0 introduces GADTs (Generalized Algebraic Data Types) and first-class modules
2022
OCaml 5.0 released with multicore support and effect handlers
2023
OCaml compiler receives ACM SIGPLAN Programming Languages Software Award

Notable Uses & Legacy

Jane Street

Quantitative trading firm uses OCaml for almost all of their trading infrastructure, processing billions of dollars daily.

Meta (Facebook)

Flow (JavaScript type checker), Hack (PHP successor), and Infer (static analyzer) are all written in OCaml.

Docker

The original Docker for Mac and Windows used the MirageOS unikernel library written in OCaml.

Airbus

Safety-critical software verification using ASTRÉE analyzer, proving absence of runtime errors in A340 flight control software.

Tezos

Blockchain platform written entirely in OCaml for its formal verification capabilities.

Coq Proof Assistant

Major formal verification tool written in OCaml, used to verify mathematical theorems and software correctness.

Language Influence

Influenced By

ML Caml Light Standard ML Lisp

Influenced

F# Rust Scala Haskell ReasonML Elm

Running Today

Run examples using the official Docker image:

docker pull ocaml/opam:alpine

Example usage:

docker run --rm -v $(pwd):/app -w /app ocaml/opam:alpine ocaml hello.ml

Topics Covered

Last updated: