let to_let_or_not_to_let () : (unit,string) result Lwt.t =
let ( let* ) (r : ('a,'b) result) (f : 'a -> ('c, 'b) result Lwt.t) : ('c,'b) result Lwt.t =
match r with
| Ok r -> f r
| Error _ as e -> Lwt.return e in
let* _ : string = Ok "string" in
let%lwt s = Lwt.return (Ok "another") in
let* _ : string = s in
let* _ = Error "string" in
Lwt.return (Ok ())
let outer () =
to_let_or_not_to_let ()
|> Lwt_main.run
I don’t use the syntax extension (the let%lwt) so I’m not sure what’s idiomatic for this use case. I don’t know if there are established guidelines for mixing the syntax extension and the binding operators. It’s definitely ok for the compiler, but Idk what the human reviewers who have encountered this sort of code a lot think about it.
That being said, in tezos we have some mixed lwt, result, and lwt+result monads all working side-by-side. We do this with multiple operators:
module Lwt_result_syntax : sig
val ( let* ) :
('a, 'e) result Lwt.t ->
('a -> ('b, 'e) result Lwt.t) ->
('b, 'e) result Lwt.t
val ( let*! ) : 'a Lwt.t -> ('a -> 'b Lwt.t) -> 'b Lwt.t
val ( let*? ) : ('a, 'e) result -> ('a -> ('b, 'e) result Lwt.t) -> ('b, 'e) result Lwt.t
(* some other helpers *)
end
Essentially we have the three binders which corresponds to the three different monads that you could be binding from: let* when binding from the full combined monad, let*? (where the ? represents the uncertainty of errors) when binding from a result, and let*! (where the ! represents the compulsory waiting for the resolution of the promise) when binding from an Lwt promise.
This would give you
let to_let_or_not_to_let () : (unit,string) result Lwt.t =
let open Lwt_result_syntax in
let*? _ : string = Ok "string" in
let*! s = Lwt.return (Ok "another") in
let*? _ : string = s in
let*? _ = Error "string" in
return_unit
(That’s a literal translation of your example; what you’d actually do is use let* _ = Lwt.return (Ok "another") in instead of the !-? sequence in the middle.)
We also have syntax modules for result-only blocks and lwt-only blocks. And even for lwt-option and option-only blocks.