package tezos-error-monad

  1. Overview
  2. Docs
type error = TzCore.error = ..
include Tezos_lwt_result_stdlib.Lwtreslib.TRACED_MONAD with type 'error trace := 'error TzTrace.trace

Import the non-traced modules as-is

include Bare_sigs.Monad.S

The tower of monads

The Lwt monad: for concurrency

module Lwt_syntax : sig ... end

Syntax module for Lwt. This is intended to be opened locally in functions which use Lwt for control-flow. Within the scope of this module, the code can include binding operators, leading to a let-style syntax.

The (generic) Result monad: for success/failure

module Result_syntax : sig ... end

Syntax module for Result. This is intended to be opened locally in functions which use result for control-flow. Within the scope of this module, the code can include binding operators, leading to a let-style syntax.

The combined Lwt+Result monad: for concurrent successes/failures

module Lwt_result_syntax : sig ... end

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.

module Traced_result_syntax : sig ... end
module Lwt_traced_result_syntax : sig ... end
include Sig.MONAD_EXTENSION with type error := error and type 'error trace := 'error TzTrace.trace
type tztrace = error TzTrace.trace
type 'a tzresult = ('a, tztrace) result
val classify_trace : tztrace -> Error_classification.t
val return : 'a -> ('a, 'e) result Lwt.t
val return_unit : (unit, 'e) result Lwt.t
val return_none : ('a option, 'e) result Lwt.t
val return_some : 'a -> ('a option, 'e) result Lwt.t
val return_nil : ('a list, 'e) result Lwt.t
val return_true : (bool, 'e) result Lwt.t
val return_false : (bool, 'e) result Lwt.t
val (>>=) : 'a Lwt.t -> ('a -> 'b Lwt.t) -> 'b Lwt.t

more globals

val (>|=) : 'a Lwt.t -> ('a -> 'b) -> 'b Lwt.t
val ok : 'a -> ('a, 'e) result
val error : 'e -> ('a, 'e TzTrace.trace) result
val (>>?) : ('a, 'e) result -> ('a -> ('b, 'e) result) -> ('b, 'e) result
val (>|?) : ('a, 'e) result -> ('a -> 'b) -> ('b, 'e) result
val fail : 'e -> ('a, 'e TzTrace.trace) result Lwt.t
val (>>=?) : ('a, 'e) result Lwt.t -> ('a -> ('b, 'e) result Lwt.t) -> ('b, 'e) result Lwt.t
val (>|=?) : ('a, 'e) result Lwt.t -> ('a -> 'b) -> ('b, 'e) result Lwt.t
val (>>?=) : ('a, 'e) result -> ('a -> ('b, 'e) result Lwt.t) -> ('b, 'e) result Lwt.t
val (>|?=) : ('a, 'e) result -> ('a -> 'b Lwt.t) -> ('b, 'e) result Lwt.t
val pp_print_trace : Format.formatter -> error TzTrace.trace -> unit
val pp_print_top_error_of_trace : Format.formatter -> error TzTrace.trace -> unit

Pretty-prints the top error of a trace

val trace_encoding : error TzTrace.trace Data_encoding.t
val result_encoding : 'a Data_encoding.t -> 'a tzresult Data_encoding.t

A serializer for result of a given type

val record_trace : 'err -> ('a, 'err TzTrace.trace) result -> ('a, 'err TzTrace.trace) result

record_trace err res is either res if res is Ok _, or it is Error (Trace.cons err tr) if res is Error tr.

In other words, record_trace err res enriches the trace that is carried by res (if it is carrying a trace) with the error err. It leaves res untouched if res is not carrying a trace.

You can use this to add high-level information to potential low-level errors. E.g.,

record_trace
   Failure_to_load_config
   (load_data_from_file config_encoding config_file_name)

Note that record_trace takes a fully evaluated error err as argument. It means that, whatever the value of the result res, the error err is evaluated. This is not an issue if the error is a simple expression (a literal or a constructor with simple parameters). However, for any expression that is more complex (e.g., one that calls a function) you should prefer record_trace_eval.

val trace : 'err -> ('b, 'err TzTrace.trace) result Lwt.t -> ('b, 'err TzTrace.trace) result Lwt.t

trace is identical to record_trace but applies to a promise. More formally, trace err p is a promise that resolves to Ok v if p resolves to Ok v, or it resolves to Error (Trace.cons err tr) if res resolves to Error tr.

In other words, trace err p enriches the trace that p resolves to (if it does resolve to a trace) with the error err. It leaves the value that p resolves to untouched if it is not a trace.

You can use this to add high-level information to potential low-level errors.

Note that, like record_trace, trace takes a fully evaluated error as argument. For a similar reason as explained there, you should only use trace with simple expressions (literal or constructor with simple parameters) and prefer trace_eval for any other expression (such as ones that include functions calls).

val record_trace_eval : (unit -> 'err) -> ('a, 'err TzTrace.trace) result -> ('a, 'err TzTrace.trace) result

record_trace_eval is identical to record_trace except that the error that enriches the trace is wrapped in a function that is evaluated only if it is needed. More formally record_trace_eval mkerr res is res if res is Ok _, or it is Error (Trace.cons (mkerr ()) tr) if res is Error tr.

You can achieve the same effect by hand with

match res with
| Ok _ -> res
| Error tr -> Error (Trace.cons (mkerr ()) tr)

Prefer record_trace_eval over record_trace when the enriching error is expensive to compute or heavy to allocate.

val trace_eval : (unit -> 'err) -> ('b, 'err TzTrace.trace) result Lwt.t -> ('b, 'err TzTrace.trace) result Lwt.t

trace_eval is identical to trace except that the error that enriches the trace is wrapped in a function that is evaluated only if and when it is needed. More formally trace_eval mkerr p is a promise that resolves to Ok v if p resolves to Ok v, or it resolves to Error (Trace.cons (mkerr ()) tr) if p resolves to Error tr.

You can achieve the same effect by hand with

p >>= function
| Ok _ -> p
| Error tr ->
   Lwt.return (Error (Trace.cons (mkerr ()) tr))

Note that the evaluation of the error can be arbitrarily delayed. Avoid using references and other mutable values in the function mkerr.

Prefer trace_eval over trace when the enriching error is expensive to compute or heavy to allocate or when evaluating it requires the use of Lwt.

val error_unless : bool -> 'err -> (unit, 'err TzTrace.trace) result

error_unless flag err is Ok () if b is true, it is Error (Trace.make err) otherwise.

val error_when : bool -> 'err -> (unit, 'err TzTrace.trace) result

error_when flag err is Error (Trace.make err) if b is true, it is Ok () otherwise.

val fail_unless : bool -> 'err -> (unit, 'err TzTrace.trace) result Lwt.t

fail_unless flag err is Lwt.return @@ Ok () if b is true, it is Lwt.return @@ Error (Trace.make err) otherwise.

val fail_when : bool -> 'err -> (unit, 'err TzTrace.trace) result Lwt.t

fail_when flag err is Lwt.return @@ Error (Trace.make err) if b is true, it is Lwt.return @@ Ok () otherwise.

val unless : bool -> (unit -> (unit, 'trace) result Lwt.t) -> (unit, 'trace) result Lwt.t

unless b f is f () if b is false and it is a promise already resolved to Ok () otherwise.

You can use unless to avoid having to write an if statement that you then need to populate entirely to satisfy the type-checker. E.g, you can write unless b f instead of if not b then f () else return_unit.

val when_ : bool -> (unit -> (unit, 'trace) result Lwt.t) -> (unit, 'trace) result Lwt.t

when_ b f is f () if b is true and it is a promise already resolved to Ok () otherwise.

You can use when_ to avoid having to write an if statement that you then need to populate entirely to satisfy the type-checker. E.g, you can write when_ b f instead of if b then f () else return_unit.

val dont_wait : (unit -> (unit, 'trace) result Lwt.t) -> ('trace -> unit) -> (exn -> unit) -> unit

Wrapper around Lwt_utils.dont_wait

OCaml

Innovation. Community. Security.