Skip to content
Lesson 3 of 7

Step 1 of 5 · Reading · ~2 min

Learn

Lazy Evaluation and Sequences

OCaml is strict by default (eager evaluation), but you can opt into laziness with lazy.

let expensive = lazy (
    print_endline "computing...";
    1 + 1
)

(* Not computed yet *)

let () = print_endline (string_of_int (Lazy.force expensive))
(* prints "computing..." then "2" *)

let () = print_endline (string_of_int (Lazy.force expensive))
(* prints "2" only — cached after first force *)

Lazy.force evaluates if needed; subsequent forces return the cached value.

'a lazy_t is the type. Pattern match with lazy:

let rec take n (lazy seq) =
    if n = 0 then []
    else match seq with
        | Cons (x, rest) -> x :: take (n - 1) rest
        | Nil -> []

Building a lazy sequence type:

type 'a stream = Cons of 'a * 'a stream Lazy.t | Nil

(* Generate naturals 1, 2, 3, ... lazily *)
let rec naturals_from n = Cons (n, lazy (naturals_from (n + 1)))

let take n s =
    let rec aux n s acc =
        if n = 0 then List.rev acc
        else match s with
            | Nil -> List.rev acc
            | Cons (x, rest) -> aux (n - 1) (Lazy.force rest) (x :: acc)
    in
    aux n s []

let first_5 = take 5 (naturals_from 1)
(* [1; 2; 3; 4; 5] — only computes 5 elements *)

Seq in the stdlib is the same idea, standardised. 'a Seq.t is unit -> 'a Seq.node, where a node is Seq.Nil or Seq.Cons of 'a * 'a Seq.t - the sequence is a function, which is exactly why it is lazy:

let rec naturals_from n = fun () -> Seq.Cons (n, naturals_from (n + 1))

let rec take n s =
    if n <= 0 then Seq.empty
    else fun () ->
        match s () with
        | Seq.Nil -> Seq.Nil
        | Seq.Cons (x, rest) -> Seq.Cons (x, take (n - 1) rest)

let () = Seq.iter print_int (take 5 (naturals_from 1))
(* 12345 *)

Later releases added Seq.take and Seq.unfold (4.14 and 4.11). This course's grader is OCaml 4.09, so write those two helpers yourself, as above, rather than reaching for them.

Use cases:

  • Infinite sequences (primes, Fibonacci, Pi digits)
  • Streaming over big files
  • Memoization
  • Building computation graphs to evaluate later

Most OCaml code is strict. Reach for lazy when you really need to defer work.

Up nextFormat Module PowerLazy Evaluation and Sequences

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…