Reading — step 1 of 5
Learn
~2 min readLazy 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 module in stdlib gives you this for free:
let rec naturals_from n =
Seq.cons n (fun () -> Seq.uncons (naturals_from (n + 1)) |> Option.get |> snd)
(* Cleaner with Seq combinators *)
let first_5 = Seq.unfold (fun n -> Some (n, n + 1)) 1 |> Seq.take 5 |> List.of_seq
Seq.t is unit -> 'a node where node is Cons of 'a * 'a t | Nil. Lazy by construction.
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.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…