Это может помочь заметить, что замыкания функций по существу эквивалентны ленивым значениям:
lazy n : 'a Lazy.t <=> (fun () -> n) : unit -> 'a
force x : 'a <=> x () : 'a
Таким образом, тип 'a llist
эквивалентен
type 'a llist = 'a cell Lazy.t
т.е. значение ленивой ячейки.
Реализация карты может иметь больше смысла с точки зрения приведенного выше определения
let rec map f lst =
match force lst with
| Nil -> lazy Nil
| Cons (hd,tl) -> lazy (Cons (f hd, map f tl))
Перевод этого обратно в замыкания:
let rec map f lst =
match lst () with
| Nil -> (fun () -> Nil)
| Cons (hd,tl) -> (fun () -> Cons (f hd, map f tl))
Аналогично с добавлением
let rec append a b =
match force a with
| Nil -> b
| Cons (hd,tl) -> lazy (Cons (hd, append tl b))
становится
let rec append a b =
match a () with
| Nil -> b
| Cons (hd,tl) -> (fun () -> Cons (hd, append tl b))
Я обычно предпочитаю использовать синтаксис lazy
, поскольку он делает более понятным, что происходит.
Также обратите внимание, что ленивая подвеска и крышка не являются точным эквивалентом. Например,
let x = lazy (print_endline "foo") in
force x;
force x
печать
foo
* +1032 * тогда
let x = fun () -> print_endline "foo" in
x ();
x ()
печать
foo
foo
Разница в том, что force
вычисляет значение выражения ровно один раз .