OCaml
Fast, safe functional programming.
OCaml is a functional language with a powerful type system and a fast native compiler. It is used for compilers, static analysis tools, formal verification and finance (Jane Street runs much of its trading on OCaml). Rust's first compiler was written in OCaml, and Meta's Hack and Flow type checkers use it.
Why learn OCaml?
OCaml shows how far a type system can take you: fast programs that are very hard to break.
- Fast: native code with a quick compiler.
- Safe: type inference and pattern matching catch bugs at compile time.
- Multicore: OCaml 5 adds parallel domains and effect handlers.
Set up and run your first program
Install opam (the OCaml package manager), then the Dune build tool and the utop interactive shell.
opam init
opam install dune utop
ocaml hello.mllet () =
let name = "Ada" in
Printf.printf "Hello, AI! Welcome to OCaml, %s.\n" nameutop for a friendly interactive shell; end expressions with ;; there.Values and types
let binds immutable values. Integers and floats are separate types with separate operators: + for ints and +. for floats.
let layers = 32
let lr = 3e-4
let model = "llama3.1"
let fp16_gb params = params *. 2.0 /. 1e9
let () =
Printf.printf "%s: %d layers, lr %g, %.1f GB\n" model layers lr (fp16_gb 8.03e9)Functions and recursion
Functions are curried and can be partially applied. let rec defines recursive functions, the usual way to loop.
let square x = x * x
let rec sum = function
| [] -> 0
| h :: t -> h + sum t
let params layers width = 12 * layers * width * width
let params_4096 = params 32 (* partial application *)
let () =
Printf.printf "%d %d %d\n" (square 12) (sum [1; 2; 3]) (params_4096 4096)Lists and higher-order functions
List.map, List.filter and List.fold_left handle most collection work. The |> pipe keeps chains readable.
let vram = [ ("H100", 80); ("H200", 141); ("RTX 5090", 32) ]
let () =
vram
|> List.filter (fun (_, gb) -> gb >= 80)
|> List.map fst
|> String.concat ", "
|> print_endline;
let total = List.fold_left (fun acc (_, gb) -> acc + gb) 0 vram in
Printf.printf "total %d GB\n" totalVariants, records and pattern matching
Variant types model choices, records hold named fields, and the compiler warns if a match misses a case.
type gpu = { name : string; vram : int }
type device = Cpu | Gpu of gpu | Tpu of int
let describe = function
| Cpu -> "CPU"
| Gpu { name; vram } when vram >= 80 -> "data center GPU " ^ name
| Gpu { name; vram } -> Printf.sprintf "GPU %s (%d GB)" name vram
| Tpu v -> Printf.sprintf "TPU v%d" v
let () = List.iter (fun d -> print_endline (describe d))
[ Cpu; Gpu { name = "H100"; vram = 80 }; Tpu 5 ]Modules, options and errors
Modules group code; signatures hide details. option replaces null, and result represents success or error.
module Vram : sig
val fit : model_gb:int -> vram_gb:int -> (int, string) result
end = struct
let fit ~model_gb ~vram_gb =
if model_gb <= vram_gb then Ok (vram_gb - model_gb)
else Error "model does not fit"
end
let () =
match Vram.fit ~model_gb:16 ~vram_gb:24 with
| Ok free -> Printf.printf "free: %d GB\n" free
| Error e -> print_endline e;
print_endline (Option.value (List.assoc_opt "B200" [ ("H100", "80") ]) ~default:"unknown")AI with OCaml
OCaml is used in AI mainly for tooling and safe infrastructure: ML compilers and DSLs, verified code, and trading systems that use models. Libraries include OCaml bindings to PyTorch (ocaml-torch) and Owl for scientific computing, and LLM APIs are easy to call with cohttp and yojson.
The essential libraries
Gradient descent from scratch
Fit y = 3x + 0.5 using arrays and a for loop.
let () =
let n = 100 in
let xs = Array.init n (fun i -> -1.0 +. 2.0 *. float i /. float (n - 1)) in
let ys = Array.map (fun x -> 3.0 *. x +. 0.5) xs in
let w = ref 0.0 and b = ref 0.0 in
for _ = 1 to 500 do
let gw = ref 0.0 and gb = ref 0.0 in
Array.iteri (fun i x ->
let err = !w *. x +. !b -. ys.(i) in
gw := !gw +. 2.0 *. err *. x /. float n;
gb := !gb +. 2.0 *. err /. float n) xs;
w := !w -. 0.1 *. !gw;
b := !b -. 0.1 *. !gb
done;
Printf.printf "w = %.2f, b = %.2f\n" !w !bBuild an AI agent in OCaml
With cohttp-lwt-unix for HTTP and yojson for JSON (install both with opam), OCaml can run the tool-calling loop.
(* opam install cohttp-lwt-unix yojson *)
open Lwt.Syntax
module J = Yojson.Safe
module U = Yojson.Safe.Util
let url = Uri.of_string "http://localhost:11434/v1/chat/completions"
let tools = J.from_string {|[{"type":"function","function":{"name":"get_weather","description":"Weather for a city",
"parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}}]|}
let chat messages =
let body = `Assoc [ ("model", `String "llama3.1"); ("messages", `List messages); ("tools", tools) ] in
let* _, b = Cohttp_lwt_unix.Client.post url
~headers:(Cohttp.Header.init_with "Content-Type" "application/json")
~body:(Cohttp_lwt.Body.of_string (J.to_string body)) in
let+ s = Cohttp_lwt.Body.to_string b in
J.from_string s |> U.member "choices" |> U.index 0 |> U.member "message"
let rec loop messages n =
if n = 0 then Lwt.return_unit else
let* msg = chat messages in
match U.member "tool_calls" msg with
| `List (_ :: _ as calls) ->
let replies = List.map (fun c ->
let args = J.from_string (U.to_string (U.member "arguments" (U.member "function" c))) in
let city = U.to_string (U.member "city" args) in
`Assoc [ ("role", `String "tool"); ("tool_call_id", U.member "id" c);
("content", `String ("It is 24°C and sunny in " ^ city ^ ".")) ]) calls in
loop (messages @ (msg :: replies)) (n - 1)
| _ -> Lwt_io.printl (U.to_string (U.member "content" msg))
let () = Lwt_main.run (loop [ `Assoc [ ("role", `String "user");
("content", `String "Should I take an umbrella in Lahore today?") ] ] 5)Build with Dune by listing cohttp-lwt-unix and yojson in the libraries field.
ollama pull llama3.1, and keep it running. The code talks to its OpenAI-compatible API at http://localhost:11434/v1, so the same program also works with vLLM, llama.cpp server or a cloud API by changing the URL, model name and adding an API key.OCaml learning roadmap
Tick items off as you go. Your progress is saved in this browser.
Beginner
Intermediate
Advanced
Projects to build
OCaml cheat sheet
| Task | Syntax |
|---|---|
| Value | let x = 5 |
| Function | let add a b = a + b |
| Float maths | 2.0 *. x +. 1.0 |
| List | [1; 2; 3] |
| Match | match x with Some v -> v | None -> 0 |
| Pipe | xs |> List.map f |
Common mistakes
- Ints and floats need different operators (
+vs+.). - List items are separated by semicolons;
[1, 2]is a list containing one tuple. - Sequencing with
;insideifbranches needsbegin ... endor parentheses.
Where to go next
- OCaml.org — official tutorials
- Real World OCaml — free book
- OCaml Discuss — community
On TensorCore.si: Haskell volume, F# volume.
Keyboard: [ previous language · ] next language · / search the library