I think I just stumbled on an interesting behaviour of the new let-binding syntax: it can make the binding body lazy. And this can be used to express ‘alternative’/‘or’ behaviour for various types e.g. option
. Can someone take a look at my comment (and code) and confirm if my reasoning is correct?
Yes. As someone pointed out a semigroup is sufficient here. The monad is “too powerful”, and you could replace the let x =
with let () =
in your code. As another option (semantically the same), define
let (||=) x f = match x with None -> f () | Some _ as y -> y
and compare
let|| () = Some 0 in let|| () = Some 1 in Some 2;;
Some 0 ||= fun () -> Some 1 ||= fun () -> Some 2;;
I think that’s a matter of taste. If we want something shorter:
let (||~) x y = match x with None -> Lazy.force y | Some _ as r -> r;;
Some 0 ||~ lazy (Some 1) ||~ lazy (Some 2);;
Thanks for the feedback. What struck me about the let-binding approach here was that it automatically makes the binding body lazy. This is something I’ve seen before only for the intrinsic %sequor
(i.e. (or)
and (||)
), oh and for lazy
too of course.
But the let-binding is configurable, which is the really new thing. Still trying to decide whether that is cool or just too confusing compared to normal idiomatic OCaml. Guess I need to work through some more examples. At least one other comes to mind, a limited ‘if-let’, e.g.:
# let (let-?) option f = match option with
| Some x -> f x
| None -> ();;
val ( let-? ) : 'a option -> ('a -> unit) -> unit = <fun>
# let-? x = Some "1" in print_endline x;;
1
- : unit = ()
# let-? x = None in print_endline x;;
- : unit = ()
Yes, or to put it in other words, this is the first user-definable binding construct. The and
part is also interesting as it allows passing nested pairs without using nested parentheses.
The let-?
is available as Option.iter
, though the code becomes longer.