Is it possible to do lazy initialization of immutable record fields in OCaml?
If you don’t mind altering the type slightly, just use Lazy.t
:
(* Basic version, normal initialisation *)
type t = { foo : foo }
let v = { foo = foo () }
(* With lazy *)
type t_lazy = { foo_lazy : foo Lazy.t }
let v_lazy = { foo_lazy = lazy (foo ()) }
It means that you have to use Lazy.force
at the use points, but with OCaml 4.x it’s mostly free, and even with OCaml 5 it’s not that expensive.
2 Likes
Hm, ok. Do I have to use Lazy.force
at each usage? Or only once?
You have to use Lazy.force
every time (or a lazy pattern). These are the only ways to convert from foo Lazy.t
into foo
.
If it’s the heavy syntax that’s bothering you, you could try lazy patterns:
(* Normal record *)
let x = v.foo
(* With Lazy.force *)
let y = Lazy.force v_lazy.foo_lazy
(* Alternatives, both equivalent to the Lazy.force version *)
let y = match v_lazy with { foo_lazy = lazy foo } -> foo
let { foo_lazy = lazy y } = v_lazy
Although it’s only going to be lighter if you read several lazy fields at the same time.
1 Like
A slightly shorter variant would also be:
let lazy y = v_lazy.foo_lazy
4 Likes