Jackson Tale
Jackson Tale

Reputation: 25812

Lazy.from_fun and Lazy.from_val

I am just curious about these two functions in Lazy.

Lazy.from_fun

From the doc:

val from_fun : (unit -> 'a) -> 'a t 

from_fun f is the same as lazy (f()) but slightly more efficient.

I then had a look at the source

let from_fun (f : unit -> 'arg) =
  let x = Obj.new_block Obj.lazy_tag 1 in
  Obj.set_field x 0 (Obj.repr f);
  (Obj.obj x : 'arg t)

I guess Obj is used to directly allocate memories for from_fun. But why exactly does it boost the efficiency? or what is the difference between Lazy.from_fun and lazy (f())?

Lazy.from_val

val from_val : 'a -> 'a t

from_val v returns an already-forced suspension of v. 
This is for special purposes only and should not be confused with lazy (v).

I really do not understand these. To me, Lazy.from_val 5 and lazy(5) both returns int lazy.t which has a concrete value of 5. Why is Lazy.from_val is for special purposes? and what kind of special purposes?

Upvotes: 1

Views: 94

Answers (1)

camlspotter
camlspotter

Reputation: 9030

It's just my guess: let's compare the following:

let z1 = lazy (print_newline ())
let z2 = Lazy.from_fun print_newline

using ocamlc -dlambda:

(setglobal Lz!
  (let
    (z1/1008 =
       (makemutable 246
         (function param/1012 (apply (field 31 (global Pervasives!)) 0a)))
     z2/1009 =
       (apply (field 2 (global Lazy!)) (field 31 (global Pervasives!))))
    (makeblock 0 z1/1008 z2/1009)))

z1 is a lazy value created from a function of the code function param/1012 -> Pervasives.print_newline (), while z2 is created directly from Pervasives.print_newline. z1 can be slightly inefficient because of the extra lambda abstraction.

Just as the documentation says, Lazy.from_val simply creates a lazy value from an already computed value without any suspension. You can check it by trying Lazy.from_val (print_string "hello") and lazy (print_string "hello"). The former immediately prints hello, but the latter does not.

Upvotes: 2

Related Questions