OCaml 惰性求值:'a lazy_t vs unit -> 'a

OCaml lazy evaluation: 'a lazy_t vs unit -> 'a

两者实现相同的目标

# let x = fun () -> begin print_endline "Hello"; 1 end;;
val x : unit -> int = <fun>
# x ();;
Hello
- : int = 1
# let y = lazy begin print_endline "World"; 2 end;;
val y : int lazy_t = <lazy>
# Lazy.force y;;
World
- : int = 2

有什么理由比另一个更受青睐?哪个效率更高?

首先,它们的行为不一样,尝试再做一次Lazy.force y,你会注意到不同之处,不再打印"World"消息,所以计算不重复,因为结果在惰性值中被记住。

这是惰性计算和 thunk 之间的主要区别。他们都将计算推迟到他们被迫的时候。但是 thunk 每次都会计算它的主体,其中惰性值将被计算一次,计算结果将被记忆。

在引擎盖下,惰性值被实现为带有特殊标志的 thunk 对象。当运行时第一次调用惰性值时,它用计算结果替换 thunk 的主体。所以,在第一次调用Lazy.force y之后,y对象实际上变成了一个整数2。因此对 Lazy.force 的后续调用什么也不做。

Lazy.force returns 相同的值,无需重新计算。

例子

let ra = ref 0 ;;
let y = lazy (ra:= !ra+1);;
Lazy.force y;;
# Lazy.force y;;
- : unit = ()
# !ra;;
- : int = 1
# Lazy.force y;;
- : unit = ()
# !ra;;
- : int = 1