Monad.Lwt_result_syntax
Syntax module for Lwt+Result. This is intended to be opened locally in functions which use Lwt and result
for control-flow. Within the scope of this module, the code can include binding operators, leading to a let
-style syntax.
See also Lwt
, Result
, and Lwt_result
.
return x
is Lwt.return (Ok x)
or Lwt_result.return x
.
return_some x
is Lwt.return (Ok (Some x))
.
Note that we do not provide return_ok
nor return_error
. Both of these functions are possible but somewhat confusing and rarely useful in practice. If you need to carry result
s within a LwtResult-monad computation (yielding values of the type (('a, 'e) result, 'e) result Lwt.t
), you need to do so by hand: return (Ok …)
and return (Error …)
.
val let* :
('a, 'e) Stdlib.result Lwt.t ->
('a -> ('b, 'e) Stdlib.result Lwt.t) ->
('b, 'e) Stdlib.result Lwt.t
let*
is a binding operator alias for Lwt_result
.bind.
let+
is a binding operator alias for Lwt_result
.map.
Note that we do not provide and*
nor and+
. Both of these are possible but their type is unsatisfying because the errors do not compose well. You can use both
(below) if need be.
lwt_map_error
is an Lwt-aware variant of Result.map_error
. It is intended for mapping the errors of Lwt-result values. The main use of this function is for mixing results that carry different types of errors.
E.g., considering fetch : unit -> (string, unit) result Lwt.t
and emit : string -> (unit, int) result Lwt.t
, you can write
let* data = lwt_map_error (fun () -> "fetching failed") @@ fetch () in
let* () =
lwt_map_error (fun code -> Format.asprintf "emit failed (%d)")
@@ emit data
in
..
The following values are for mixing expressions that are Lwt-only or Result-only within the LwtResult monad. Note that there are fundamental differences between result
and Lwt.t
: the former can be simply matched on (i.e., it is possible to get out of the monad at any point) whereas the latter can only be bound on (i.e., it is not possible to get out of the monad). In addition, the former is for aborting computations on failures whereas the latter is for waiting before continuing.
Still, from a syntax point-of-view, both are handled the same way: with a specialised binding operator.
let*!
is for binding Lwt-only expressions into the LwtResult combined monad.
let open Lwt_result_syntax in
let* x = … in
let*! y = … in
return (x + y)
val let*? :
('a, 'e) Stdlib.result ->
('a -> ('b, 'e) Stdlib.result Lwt.t) ->
('b, 'e) Stdlib.result Lwt.t
let*?
is for binding the value from Result-only expressions into the LwtResult combined monad.
let open Lwt_result_syntax in
let* x = … in
let*? y = … in
…
Note that you can mix let*
, let*!
, and let*?
as needed, within a single expression.
let do_thing param =
let open Lwt_result_syntax in
let*? () = check_p param in (* Result-only for parameter checking *)
let*! () = log "starting doing the thing" in (* Lwt-only for infallible logging *)
let* r = thing param in
let*! () = log "done doing the thing" in (* Lwt-only for infallible logging *)
return r
join
is the joining of concurrent success/failure unit values.
all
is the joining of concurrent success/failure non-unit values.