123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2020 Nomadic Labs <contact@nomadic-labs.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)(** {1 Lwt, result, and Lwt-result monad operators}
This module provides the necessary functions and operators to use Lwt,
result and Lwt-result as a monad.
{2 Basics}
The three, tiered monads have each their full set of operators:
The Lwt monad:
{ul
{li {!Lwt.return} for return,}
{li {!Lwt.bind} or {!(>>=)} for bind, and}
{li {!Lwt.map} or {!(>|=)} for map.}
}
The result monad:
{ul
{li {!Result.ok} or {!ok} for return,}
{li {!Result.bind} or {!(>>?)} for bind, and}
{li {!Result.map} {!(>|?)} for map.}
}
In addition, {!Result.error} or {!error} is for failures within the result
monad.
The Lwt-result monad:
{ul
{li {!return} or {!Lwt.return_ok} for return,}
{li {!(>>=?)} for bind, and}
{li {!(>|=?)} for map.}
}
In addition, {!fail} is for the failure within the Lwt-result combined
monad.
Note that future improvements are planned to (a) make those more uniform,
(b) allow the opening of selected infix operators only, and (c) provide
[let*]-binds.
{2 Preallocated values}
The module also provides preallocated values for the common types:
- {!unit_s} (resp {!unit_e}) (resp {!unit_es}) is [Lwt.return ()] (resp
[Ok ()]) (resp [Lwt.return (Ok ())]),
- {!none_s} (resp {!none_e}) (resp {!none_es}) is [Lwt.return None] (resp
[Ok None]) (resp [Lwt.return (Ok None)]),
- etc. (see full inventory below)
Note that some of these values are also available in their dedicated
modules. E.g., [none_*] are available in {!Option}.
{2 Joins}
The {!join_p} function takes a list of promises [ps] and returns a single
promise [p] that resolves with [()] when all the promises of [ps] have
resolved.
The {!all_p} function takes a list of promises [ps] and returns a single
promise [p] that resolves when all the promises of [ps] have resolved. The
value [p] resolves to is the list of values the promises of [ps] resolve to.
The order is preserved.
The {!both_p} function takes two promises [p1] and [p2] and returns a single
promise [p] that resolves when both promises [p1] and [p2] have resolved.
The value [p] resolves to is the tuple of values the promises [p1] and [p2]
resolve to.
Note that like all [_p] functions, these functions have a best-effort
semantic: they only resolve once all the underlying promises have resolved.
The [_e] variants are equivalent for the result monad: the final result is
[Ok] if all the underlying results are [Ok].
The [_es] variants are equivalent for the Lwt-result monad: the final
promise resolves to [Ok] if all the underlying promise resolve to [Ok].
*)moduletypeS=sig(** lwt monad *)val(>>=):'aLwt.t->('a->'bLwt.t)->'bLwt.tval(>|=):'aLwt.t->('a->'b)->'bLwt.t(** result monad *)valok:'a->('a,'trace)resultvalerror:'error->('a,'error)resultval(>>?):('a,'trace)result->('a->('b,'trace)result)->('b,'trace)resultval(>|?):('a,'trace)result->('a->'b)->('b,'trace)result(** lwt-result combined monad *)valok_s:'a->('a,'trace)resultLwt.tvalreturn:'a->('a,'trace)resultLwt.tvalerror_s:'error->('a,'error)resultLwt.tvalfail:'error->('a,'error)resultLwt.tval(>>=?):('a,'trace)resultLwt.t->('a->('b,'trace)resultLwt.t)->('b,'trace)resultLwt.tval(>|=?):('a,'trace)resultLwt.t->('a->'b)->('b,'trace)resultLwt.t(** Mixing operators *)(** All operators follow this naming convention:
- the first character is [>]
- the second character is [>] for [bind] and [|] for [map]
- the next character is [=] for Lwt or [?] for Error
- the next character (if present) is [=] for Lwt or [?] for Error, it is
only used for operator that are within both monads. *)val(>>?=):('a,'trace)result->('a->('b,'trace)resultLwt.t)->('b,'trace)resultLwt.tval(>|?=):('a,'trace)result->('a->'bLwt.t)->('b,'trace)resultLwt.t(** preallocated in-monad values *)valunit_s:unitLwt.tvalunit_e:(unit,'trace)resultvalunit_es:(unit,'trace)resultLwt.tvalnone_s:'aoptionLwt.tvalnone_e:('aoption,'trace)resultvalnone_es:('aoption,'trace)resultLwt.tvalsome_s:'a->'aoptionLwt.tvalsome_e:'a->('aoption,'trace)resultvalsome_es:'a->('aoption,'trace)resultLwt.tvalnil_s:'alistLwt.tvalnil_e:('alist,'trace)resultvalnil_es:('alist,'trace)resultLwt.tvaltrue_s:boolLwt.tvaltrue_e:(bool,'trace)resultvaltrue_es:(bool,'trace)resultLwt.tvalfalse_s:boolLwt.tvalfalse_e:(bool,'trace)resultvalfalse_es:(bool,'trace)resultLwt.t(** additional preallocated in-monad values
this is for backwards compatibility and for similarity with Lwt *)valok_unit:(unit,'error)resultvalreturn_unit:(unit,'error)resultLwt.t(** joins *)valjoin_p:unitLwt.tlist->unitLwt.tvalall_p:'aLwt.tlist->'alistLwt.tvalboth_p:'aLwt.t->'bLwt.t->('a*'b)Lwt.tvaljoin_e:(unit,'trace)resultlist->(unit,'tracelist)resultvalall_e:('a,'trace)resultlist->('alist,'tracelist)resultvalboth_e:('a,'trace)result->('b,'trace)result->('a*'b,'tracelist)resultvaljoin_ep:(unit,'trace)resultLwt.tlist->(unit,'tracelist)resultLwt.tvalall_ep:('a,'trace)resultLwt.tlist->('alist,'tracelist)resultLwt.tvalboth_ep:('a,'trace)resultLwt.t->('b,'trace)resultLwt.t->('a*'b,'tracelist)resultLwt.tend