123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201(*****************************************************************************)(* *)(* 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 Seq}
A replacement for {!Stdlib.Seq} which
- is exception-safe,
- includes Lwt-, result- and Lwt-result-aware traversal functions.
See {!Lwtreslib} for a general description of traversors and the meaning for
the name suffixes. A full description is also below.
Note the [Seq] module (along with the [Seq_*] modules) (unlike other
modules of Lwtreslib) uses submodules to organise different monadic
traversors. This is because the implementation of the [Seq] module is
delegated to the [Seqes] library which uses functors which produces
(sub)modules.
All traversal functions that are inside the [E] submodule are within the
result monad. Note that these functions have a "fail-early" behaviour: the
traversal is interrupted as soon as any of the intermediate application
fails (i.e., returns an [Error _]).
All traversal functions that are inside the [S] submodule are within the Lwt
monad. These functions traverse the elements sequentially: the promise for a
given step of the traversal is only initiated when the promise for the
previous step is resolved. Note that these functions have a fail-early
behaviour: the traversal is interrupted if any of the intermediate promise
is rejected.
All the traversal functions that are suffixed with [_p] are within Lwt.
These functions traverse the elements concurrently: the promise for all the
steps are created immediately. The suffix [_p] is chosen for similarity with
the {!Lwt_list} functions even though, as with {!Lwt_list}'s functions there
is no parallelism involved, only concurrency. Note that these functions have
a “best-effort” behaviour: the whole-traversal promise (i.e., the promise
returned by the [_p]-suffixed function) only resolves once each of the step
promises have resolved. Even if one of the step promise is rejected, the
whole-traversal promise is only rejected once all the other step promises
have resolved.
All the traversal functions that are inside the [ES] submodule are within
the combined error-and-Lwt monad. These function traverse the elements
sequentially with a fail-early behaviour for both rejection (as an Lwt
promise) and failure (as a result).
All the traversal functions that are suffixed with [_ep] are within the
combined error-and-Lwt monad. These function traverse the elements
concurrently with a best-effort behaviour.
*)(** {2 Special consideration}
Because of the type of {!Stdlib.Seq.t}, some interactions with Lwt are not
possible. Specifically, note that the type includes the variant
[unit -> 'a node] which is not within Lwt nor within the result monad.
As a result, some of the traversals ([S.map], [E.map], etc.) cannot be
applied lazily.
Check-out the [S] variants ({!Seq_s.S}, {!Seq_e.S}, and
{!Seq_es.S}) that integrate the base sequence type better with the monads'
type. It is recommended that you use the variant as appropriate to your
traversal. Note the presence of [of_seq] in each of those variants to
convert from the standard [S.t]. *)moduletypeS=sig(** {3 Common interface with Stdlib}
Note that some functions (namely [init], [take], and [drop]) are shadowed
with exception-less versions.
Note that [once] is not shadowed. Be careful when using [once]: the
resulting sequence is {e ephemeral} and using in a non-ephemeral way
raises an exception. As a safer alternative, you can use
[Seq_e.of_seq_once] which gives you a result-based (exception-less)
ephemeral sequence. *)includemoduletypeofStdlib.Seqwithtype'at='aStdlib.Seq.tandtype'anode='aStdlib.Seq.node(** {3 Lwtreslib-specific safety-shadowing} *)valinit:when_negative_length:'err->int->(int->'a)->('at,'err)resultvaltake:when_negative_length:'err->int->'at->('at,'err)resultvaldrop:when_negative_length:'err->int->'at->('at,'err)resultmoduleE:Seqes.Sigs.SEQMON2TRAVERSORSwithtype('a,'e)mon:=('a,'e)resultwithtype('a,'e)callermon:=('a,'e)resultwithtype('a,'e)t:='aStdlib.Seq.tmoduleS:Seqes.Sigs.SEQMON1TRAVERSORSwithtype'amon:='aLwt.twithtype'acallermon:='aLwt.twithtype'at:='aStdlib.Seq.tmoduleES:Seqes.Sigs.SEQMON2TRAVERSORSwithtype('a,'e)mon:=('a,'e)resultLwt.twithtype('a,'e)callermon:=('a,'e)resultLwt.twithtype('a,'e)t:='aStdlib.Seq.t(** {3 Lwtreslib-specific extensions} *)(** Similar to {!iter} but wraps the iteration in [result Lwt.t]. All the
steps of the iteration are started concurrently. The promise [iter_ep]
resolves once all the promises of the traversal resolve. At this point it
either:
- is rejected if at least one of the promises is, otherwise
- is fulfilled with [Error _] if at least one of the promises is,
otherwise
- is fulfilled with [Ok ()] if all the promises are. *)valiter_ep:('a->(unit,'trace)resultLwt.t)->'at->(unit,'tracelist)resultLwt.t(** Similar to {!iter} but wraps the iteration in {!Lwt}. All the
steps of the iteration are started concurrently. The promise [iter_p f s]
is resolved only once all the promises of the iteration are. At this point
it is either fulfilled if all promises are, or rejected if at least one of
them is. *)valiter_p:('a->unitLwt.t)->'at->unitLwt.t(** Similar to {!iteri} but wraps the iteration in [result Lwt.t]. All the
steps of the iteration are started concurrently. The promise [iteri_ep]
resolves once all the promises of the traversal resolve. At this point it
either:
- is rejected if at least one of the promises is, otherwise
- is fulfilled with [Error _] if at least one of the promises is,
otherwise
- is fulfilled with [Ok ()] if all the promises are. *)valiteri_ep:(int->'a->(unit,'trace)resultLwt.t)->'at->(unit,'tracelist)resultLwt.t(** Similar to {!iteri} but wraps the iteration in {!Lwt}. All the
steps of the iteration are started concurrently. The promise [iter_p f s]
is resolved only once all the promises of the iteration are. At this point
it is either fulfilled if all promises are, or rejected if at least one of
them is. *)valiteri_p:(int->'a->unitLwt.t)->'at->unitLwt.t(** Similar to {!iter2} but wraps the iteration in [result Lwt.t]. All the
steps of the iteration are started concurrently. The promise
[iter2_ep f s1 s2] resolves once all the promises of the traversal resolve.
At this point it is either:
- rejected if at least one of the promises is,
- fulfilled with [Error _] if at least one of the promises is,
- fulfilled with [Ok ()] if all of the promises are.
Note that similarly to {!Stdlib.Seq.iter2} this function iterates on the
common-length prefix of the two sequences. As a result, the iteration can
be successful even if the two sequences are of different lengths. *)valiter2_ep:('a->'b->(unit,'trace)resultLwt.t)->'at->'bt->(unit,'tracelist)resultLwt.t(** Similar to {!iter2} but wraps the iteration in {!Lwt}. All the
steps of the iteration are started concurrently. The promise
[iter2_p f s1 s2] resolves once all the promises of the traversal resolve.
At this point it is either:
- rejected if at least one of the promises is,
- fulfilled with [()] if all of the promises are.
Note that similarly to {!Stdlib.Seq.iter2} this function iterates on the
common-length prefix of the two sequences. As a result, the iteration can
be successful even if the two sequences are of different lengths. *)valiter2_p:('a->'b->unitLwt.t)->'at->'bt->unitLwt.tend