janestreet / base

Standard library for OCaml
MIT License
860 stars 125 forks source link

Option.value where default is lazy? #109

Closed brendanlong closed 3 years ago

brendanlong commented 3 years ago

It comes up fairly often that we want to do something like Option.value but have the ~default argument evaluated lazily. For example, we might read configs from environment variables if they're not provided:

let default_x () =
  lazy (
    match Sys.getenv "x" with
    | Some x -> x
    | None -> assert false)

let do_thing ?x () =
  let x = Option.value ~default:(Lazy.force x) in
  ...

The problem is that the Lazy.force x gets evaluated whether or not we already have a value for x.

In our code we have a bunch of:

let do_thing ?x () =
  let x =
    match x with
    | Some x -> x
    | None -> Lazy.force default_x
  in
  ...

But that's annoying, and it's a problem when the right way of doing something (the big match statement) is harder than the wrong way (using Option.value).

I just added a helper in our code:

(* option.ml *)
let value_lazy_default t ~default =
  match t with
  | Some value -> value
  | None -> Lazy.force default
;;

But I'm curious if you'd be open to adding this to Base?

dwang20151005 commented 3 years ago

I have wanted this too!

On Thu, Apr 15, 2021 at 11:14 AM Brendan Long @.***> wrote:

It comes up fairly often that we want to do something like Option.value but have the ~default argument evaluated lazily. For example, we might read configs from environment variables if they're not provided:

let default_x () = lazy ( match Sys.getenv "x" with | Some x -> x | None -> assert false) let do_thing ?x () = let x = Option.value ~default:(Lazy.force x) in ...

The problem is that the Lazy.force x gets evaluated whether or not we already have a value for x.

In our code we have a bunch of:

let do_thing ?x () = let x = match x with | Some x -> x | None -> Lazy.force default_x in ...

But that's annoying, and it's a problem when the right way of doing something (the big match statement) is harder than the wrong way (using Option.value).

I just added a helper in our code:

( option.ml )let value_lazy_default t ~default = match t with | Some value -> value | None -> Lazy.force default ;;

But I'm curious if you'd be open to adding this to Base?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/janestreet/base/issues/109, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADSJX7CNVXKRTTGLKDBG6OTTI37F3ANCNFSM427WQFHA .

brendanlong commented 3 years ago

Just realized I already made a PR for this a while back #93

bcc32 commented 3 years ago

Closing as a duplicate, please see #93.