The only difference between this function and one that simply unwraps an option safely (ie. with a ~default argument) is that here the default argument isnāt evaluated right away but is instead a function to be called if needed. This is why Containers calls this function get_lazy (corresponding to its get_or, which preceded the stdlibās value but has the same functionality). A similar name for this function that matches the stdlibās terminology would be value_lazy.
Want something like this? with monadic syntax support, it might be nice ?
module OM = struct let (>>=) v f = match v with Some _ -> v | None -> f() end ;;
module OM :
sig val ( >>= ) : 'a option -> (unit -> 'a option) -> 'a option end
# OM.( (Some 2) >>= (fun () -> Some 1)) ;;
- : int option = Some 2
# OM.( None >>= (fun () -> Some 1)) ;;
- : int option = Some 1
The good thing about the monadic way of doing this [and Iām certainly not a fan of monads] is that you get the short-circuit behaviour of conditional-or. if youāre going to put something into stdlib, it seems like thatās important, no?
Thanks @Chet_Murthy for suggesting the Monad Way. Iāve tried the let+ and it works but I will not call it an improvement.
Judge for yourself
let ( let// ) v f = match v with Some _ -> v | None -> f ();;
let// x = Some 1 in Some 3 (* x is Some 1 *);;
let// x = None in Some 3 (* x is Some 3 *);;
let f () = print_endline "********"; Some 9;;
let// x = Some 1 in f () (* x is Some 1 *);;
let// x = None in f () (* x is Some 9 and some stars are printed *);;
Iāll probably stick with pattern matching for now.
But now Iād like to have something like that in Stdlib
module Option
...
let bind o f = match o with None -> None | Some v -> f v
..
module Syntax = struct
let ( let+ ) = bind
end
end
Someone on here some time ago came up with a let|| (let-or) operator which I noted down at the time because it seemed quite interesting. It will accept the first option which does not evaluate to None. You can make the default the last value:
let (let||) opt f =
match opt with
| Some _ -> opt
| None -> f ()
So you could have this:
# let x =
let|| () = Some 10 in
let|| () = Some 20 in
Some 30;;
- : val x : int option = Some 10
let x =
let|| () = None in
let|| () = None in
Some 30;;
- : val x : int option = Some 30
The fact that the (let||) operator automatically puts everything after the first binding into a thunk, and so on thereafter, is the nice part I think, because it gives you proper short-circuiting. I think that outweighs the slight complication of the syntax.
Iām feeling this sort of ā¦ disquiet, that thereās no way to get this same functionality using infix operators. Let is fine for sure, but it seems unfortunate that there isnāt some way to have an infix operator that implicitly lazy-i-fies its right-hand-side argument, so that we can express short-circuit-ing without using let.