* lazy vs fun
@ 2009-08-24 21:57 Warren Harris
2009-08-24 22:04 ` [Caml-list] " Jake Donham
2009-08-24 22:06 ` Stéphane Glondu
0 siblings, 2 replies; 11+ messages in thread
From: Warren Harris @ 2009-08-24 21:57 UTC (permalink / raw)
To: OCaml
Is there any advantage to using lazy evaluation in ocaml rather than
just using thunks to defer evaluation? E.g.
let x = lazy (3+4)
let y = Lazy.force x
vs:
let x = fun () -> 3+4
let y = x ()
Perhaps it's just that the type int lazy_t is more informative than
unit -> int?
Warren
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Caml-list] lazy vs fun
2009-08-24 21:57 lazy vs fun Warren Harris
@ 2009-08-24 22:04 ` Jake Donham
2009-08-24 22:15 ` Warren Harris
2009-08-24 22:06 ` Stéphane Glondu
1 sibling, 1 reply; 11+ messages in thread
From: Jake Donham @ 2009-08-24 22:04 UTC (permalink / raw)
To: OCaml
On Mon, Aug 24, 2009 at 2:57 PM, Warren Harris<warren@metaweb.com> wrote:
> Is there any advantage to using lazy evaluation in ocaml rather than just
> using thunks to defer evaluation? E.g.
>
> let x = lazy (3+4)
> let y = Lazy.force x
>
> vs:
>
> let x = fun () -> 3+4
> let y = x ()
Lazy cells don't just defer, they also memoize the returned value once
the cell is forced.
# let x = lazy (print_endline "forced"; 1);;
val x : int lazy_t = <lazy>
# Lazy.force x;;
forced
- : int = 1
# Lazy.force x;;
- : int = 1
They even memoize exceptions:
# let x = lazy (print_endline "forced"; failwith "failed");;
val x : 'a lazy_t = <lazy>
# Lazy.force x;;
forced
Exception: Failure "failed".
# Lazy.force x;;
Exception: Failure "failed".
Jake
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Caml-list] lazy vs fun
2009-08-24 21:57 lazy vs fun Warren Harris
2009-08-24 22:04 ` [Caml-list] " Jake Donham
@ 2009-08-24 22:06 ` Stéphane Glondu
2009-08-24 22:19 ` Martin Jambon
1 sibling, 1 reply; 11+ messages in thread
From: Stéphane Glondu @ 2009-08-24 22:06 UTC (permalink / raw)
To: Warren Harris; +Cc: OCaml
Warren Harris a écrit :
> Is there any advantage to using lazy evaluation in ocaml rather than
> just using thunks to defer evaluation? [...]
Two things I can think of right now: they are evaluated only once (even
if you call Lazy.force several times), and you can do pattern matching
with them.
> Perhaps it's just that the type int lazy_t is more informative than unit -> int?
That one, too.
Cheers,
--
Stéphane
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Caml-list] lazy vs fun
2009-08-24 22:06 ` Stéphane Glondu
@ 2009-08-24 22:19 ` Martin Jambon
2009-08-24 23:11 ` Martin Jambon
0 siblings, 1 reply; 11+ messages in thread
From: Martin Jambon @ 2009-08-24 22:19 UTC (permalink / raw)
To: Stéphane Glondu; +Cc: Warren Harris, OCaml
Stéphane Glondu wrote:
> Warren Harris a écrit :
>> Is there any advantage to using lazy evaluation in ocaml rather than
>> just using thunks to defer evaluation? [...]
>
> Two things I can think of right now: they are evaluated only once (even
> if you call Lazy.force several times), and you can do pattern matching
> with them.
Note that the memoization feature can be implemented like this:
let lz f =
let result = ref `None in
fun () ->
match !result with
`None ->
(try
let y = f () in
result := `Result y;
y
with e ->
result := `Exn e;
raise e
)
| `Result y -> y
| `Exn e -> raise e
# #load"unix.cma";;
# let first_date = lz Unix.gettimeofday;;
val first_date : unit -> float = <fun>
# first_date ();;
- : float = 1251151837.4585979
# first_date ();;
- : float = 1251151837.4585979
However this is slightly less efficient than how "lazy" is implemented, and of
course you don't have the nice syntax nor the (recent) pattern matching feature.
Martin
--
http://mjambon.com/
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Caml-list] lazy vs fun
2009-08-24 22:19 ` Martin Jambon
@ 2009-08-24 23:11 ` Martin Jambon
2009-08-24 23:33 ` Warren Harris
2009-08-25 5:19 ` rixed
0 siblings, 2 replies; 11+ messages in thread
From: Martin Jambon @ 2009-08-24 23:11 UTC (permalink / raw)
To: Martin Jambon; +Cc: Stéphane Glondu, Warren Harris, OCaml
Martin Jambon wrote:
> Stéphane Glondu wrote:
>> Warren Harris a écrit :
>>> Is there any advantage to using lazy evaluation in ocaml rather than
>>> just using thunks to defer evaluation? [...]
>> Two things I can think of right now: they are evaluated only once (even
>> if you call Lazy.force several times), and you can do pattern matching
>> with them.
>
>
> Note that the memoization feature can be implemented like this:
>
> let lz f =
> let result = ref `None in
> fun () ->
> match !result with
> `None ->
> (try
> let y = f () in
> result := `Result y;
> y
> with e ->
> result := `Exn e;
> raise e
> )
> | `Result y -> y
> | `Exn e -> raise e
Oops.
The following makes it possible for f to be garbage-collected:
let lz f =
let result = ref (`None f) in
fun () ->
match !result with
`None f ->
(try
let y = f () in
result := `Result y;
y
with e ->
result := `Exn e;
raise e
)
| `Result y -> y
| `Exn e -> raise e
Martin
--
http://mjambon.com/
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Caml-list] lazy vs fun
2009-08-24 23:11 ` Martin Jambon
@ 2009-08-24 23:33 ` Warren Harris
2009-08-25 5:19 ` rixed
1 sibling, 0 replies; 11+ messages in thread
From: Warren Harris @ 2009-08-24 23:33 UTC (permalink / raw)
To: Martin Jambon; +Cc: Stéphane Glondu, OCaml
On Aug 24, 2009, at 4:11 PM, Martin Jambon wrote:
>
> Oops.
> The following makes it possible for f to be garbage-collected:
>
[...]
If I understand correctly, the closure associated with f will be
collectable after the lazy_t is forced, whereas before its lifetime
would be bound to the lifetime of the lazy_t. That's very subtle. It
would have taken me some time to track that one down if it had come up
in practice. Thanks,
Warren
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Caml-list] lazy vs fun
2009-08-24 23:11 ` Martin Jambon
2009-08-24 23:33 ` Warren Harris
@ 2009-08-25 5:19 ` rixed
2009-08-25 6:29 ` David Allsopp
1 sibling, 1 reply; 11+ messages in thread
From: rixed @ 2009-08-25 5:19 UTC (permalink / raw)
To: OCaml
> Oops.
> The following makes it possible for f to be garbage-collected:
...?
Because the fact that the fun calls f does not count as a reference ?
^ permalink raw reply [flat|nested] 11+ messages in thread
* RE: [Caml-list] lazy vs fun
2009-08-25 5:19 ` rixed
@ 2009-08-25 6:29 ` David Allsopp
2009-08-25 18:09 ` rixed
0 siblings, 1 reply; 11+ messages in thread
From: David Allsopp @ 2009-08-25 6:29 UTC (permalink / raw)
To: rixed, 'OCaml'
rixed@happyleptic.org wrote:
> > Oops.
> > The following makes it possible for f to be garbage-collected:
>
> ...?
> Because the fact that the fun calls f does not count as a reference ?
The anonymous function in the second version of Martin's function doesn't
"call" [f] (at least directly): imagine if the `None case had been written
with [g]s instead:
let lz f =
let result = ref (`None f) in
fun () ->
match !result with
`None g ->
(try
let y = g () in
result := `Result y;
y
with e ->
result := `Exn e;
raise e
)
| `Result y -> y
| `Exn e -> raise e
The [fun] only "calls" (uses) [result]. In the first version, [f] could only
be collected after the [fun] had been collected (i.e. when the lazy value
itself is collected - not good). In the second version, [f] can be garbage
collected if the lazy value has already been forced (meaning that "[result =
`Result y | `Exn e]" so there will be no more references to [f]) - a clear
optimisation with no performance penalty in terms of space.
The optimisation would be irrelevant if the ocaml compiler was lazy and just
included all of the scope in the closure for [fun], but minimising (and
eliminating, where possible) closures is a critical part of ML compilers
(I'd be amazed if it's not covered in all of the books you've mentioned
previously and I wish I could remember the name usually given to the
problem... but I'm sure someone will chip in with it!)
David
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Caml-list] lazy vs fun
2009-08-25 6:29 ` David Allsopp
@ 2009-08-25 18:09 ` rixed
0 siblings, 0 replies; 11+ messages in thread
From: rixed @ 2009-08-25 18:09 UTC (permalink / raw)
To: 'OCaml'
I had to read it three times, but I now understand the issue.
I initialy though the first version was somewhat bugged :-)
Now I understand why the second one is better. This kind of
optimisation is very interresting (not capturing all the scope
when building a closure). I will look for it now.
And BTW, if I find the proper name for this technique in the
book that I'm currently reading (The Impl. of Func. Prog. Lang.)
then I will post it here to refresh your memory :)
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2009-08-25 18:09 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-08-24 21:57 lazy vs fun Warren Harris
2009-08-24 22:04 ` [Caml-list] " Jake Donham
2009-08-24 22:15 ` Warren Harris
2009-08-24 22:18 ` Jake Donham
2009-08-24 22:06 ` Stéphane Glondu
2009-08-24 22:19 ` Martin Jambon
2009-08-24 23:11 ` Martin Jambon
2009-08-24 23:33 ` Warren Harris
2009-08-25 5:19 ` rixed
2009-08-25 6:29 ` David Allsopp
2009-08-25 18:09 ` rixed
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox