Using let-binding syntax to implement option 'or'

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?

2 Likes

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.

1 Like