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.