123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867(*****************************************************************************)(* *)(* 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 List}
A replacement for {!Stdlib.List} which:
- replaces the exception-raising functions by exception-safe variants,
- provides Lwt-, result- and Lwt-result-aware traversors.
[List] is intended to shadow both {!Stdlib.List} and {!Lwt_list}. *)(** {2 Basics}
Checkout {!Lwtreslib} for an introduction to the naming and semantic
convention of Lwtreslib. In a nutshell:
- Stdlib functions that raise exceptions are replaced by safe variants
(typically returning [option]).
- The [_e] suffix is for result-aware traversors ("e" stands for "error"),
[_s] and [_p] are for Lwt-aware, and [_es] and [_ep] are for
Lwt-result-aware.
- [_e], [_s], and [_es] traversors are {i fail-early}: they stop traversal
as soon as a failure ([Error] or [Fail]) occurs; [_p] and [_ep]
traversors are {i best-effort}: they only resolve once all of the
intermediate promises have, even if a failure occurs. *)(** {2 Double-traversal and combine}
Note that double-list traversors ([iter2], [map2], etc., and also [combine])
take an additional [when_different_lengths] parameter. This is to control
the error that is returned when the two lists passed as arguments have
different lengths.
This mechanism is a replacement for {!Stdlib.List.iter2} (etc.) raising
[Invalid_argument].
Note that, as per the fail-early behaviour mentioned above, [_e], [_s], and
[_es] traversors will have already processed the common-prefix before the
error is returned.
Because the best-effort behaviour of [_p] and [_ep] is unsatisfying for this
failure case, double parallel traversors are omitted from this library.
(Specifically, it is not obvious whether nor how the
[when_different_lengths] error should be composed with the other errors.)
To obtain a different behaviour for sequential traversors, or to process
two lists in parallel, you can use {!combine} or any of the alternative that
handles the error differently: {!combine_drop}, {!combine_with_leftovers}.
Finally, the {!rev_combine} is provided to allow to avoid
multiple-reversing.
{3 Special considerations}
Because they traverse the list from right-to-left, the {!fold_right2}
function and all its variants fail with [when_different_lengths] before any
of the processing starts. Whilst this is still within the fail-early
behaviour, it may be surprising enough that it requires mentioning here.
Because they may return early, {!for_all2} and {!exists2} and all their
variants may return [Ok _] even tough the arguments have different lengths.
*)moduletypeS=sig(** {3 Trivial values} *)type'at='aStdlib.List.t=[]|(::)of'a*'alist(** in-monad, preallocated nil *)(** [nil] is [[]] *)valnil:'alist(** [nil] is [Ok []] *)valnil_e:('alist,'trace)result(** [nil] is [Lwt.return_nil] *)valnil_s:'alistLwt.t(** [nil] is [Lwt.return (Ok [])] *)valnil_es:('alist,'trace)resultLwt.t(** {3 Safe wrappers}
Shadowing unsafe functions to avoid all exceptions. *)(** {4 Safe lookups, scans, retrievals}
Return option rather than raise [Not_found], [Failure _], or
[Invalid_argument _] *)(** [hd xs] is the head (first element) of the list or [None] if the list is
empty. *)valhd:'alist->'aoption(** [tl xs] is the tail of the list (the whole list except the first element)
or [None] if the list is empty. *)valtl:'alist->'alistoption(** [nth xs n] is the [n]th element of the list or [None] if the list has
fewer than [n] elements.
[nth xs 0 = tl xs] *)valnth:'alist->int->'aoption(** [nth_opt] is an alias for [nth] provided for backwards compatibility. *)valnth_opt:'alist->int->'aoption(** [last x xs] is the last element of the list [xs] or [x] if [xs] is empty.
The primary intended use for [last] is after destructing a list:
[match l with | None -> … | Some x :: xs -> last x xs]
but it can also be used for a default value:
[last default_value_if_empty xs]. *)vallast:'a->'alist->'a(** [last_opt xs] is the last element of the list [xs] or [None] if the list
[xs] is empty. *)vallast_opt:'alist->'aoption(** [find predicate xs] is the first element [x] of the list [xs] such that
[predicate x] is [true] or [None] if the list [xs] has no such element. *)valfind:('a->bool)->'alist->'aoption(** [find_opt] is an alias for [find] provided for backwards compatibility. *)valfind_opt:('a->bool)->'alist->'aoption(** [mem ~equal a l] is [true] iff there is an element [e] of [l] such that
[equal a e]. *)valmem:equal:('a->'a->bool)->'a->'alist->bool(** [assoc ~equal k kvs] is [Some v] such that [(k', v)] is the first pair in
the list such that [equal k' k] or [None] if the list contains no such
pair. *)valassoc:equal:('a->'a->bool)->'a->('a*'b)list->'boption(** [assoc_opt] is an alias for [assoc] provided for backwards compatibility. *)valassoc_opt:equal:('a->'a->bool)->'a->('a*'b)list->'boption(** [assq k kvs] is the same as [assoc ~equal:Stdlib.( == ) k kvs]: it uses
the physical equality. *)valassq:'a->('a*'b)list->'boption(** [assq_opt] is an alias for [assq] provided for backwards compatibility. *)valassq_opt:'a->('a*'b)list->'boption(** [mem_assoc ~equal k l] is equivalent to
[Option.is_some @@ assoc ~equal k l]. *)valmem_assoc:equal:('a->'a->bool)->'a->('a*'b)list->bool(** [mem_assq k l] is [mem_assoc ~equal:Stdlib.( == ) k l]. *)valmem_assq:'a->('a*'b)list->bool(** [remove_assoc ~equal k l] is [l] without the first element [(k', _)] such
that [equal k k']. *)valremove_assoc:equal:('a->'a->bool)->'a->('a*'b)list->('a*'b)list(** [remove_assoq k l] is [remove_assoc ~equal:Stdlib.( == ) k l]. *)valremove_assq:'a->('a*'b)list->('a*'b)list(** {4 Initialisation} *)(** [init ~when_negative_length n f] is [Error when_negative_length] if [n] is
strictly negative and [Ok (Stdlib.List.init n f)] otherwise. *)valinit:when_negative_length:'trace->int->(int->'a)->('alist,'trace)result(** {4 Basic traversal} *)vallength:'alist->intvalrev:'alist->'alistvalconcat:'alistlist->'alistvalappend:'alist->'alist->'alistvalrev_append:'alist->'alist->'alistvalflatten:'alistlist->'alist(** {4 Double-list traversals}
These safe-wrappers take an explicit value to handle the case of lists of
unequal length.
*)(** [combine ~when_different_lengths l1 l2] is either
- [Error when_different_lengths] if [List.length l1 <> List.length l2]
- a list of pairs of elements from [l1] and [l2]
E.g., [combine ~when_different_lengths [] [] = Ok []]
E.g., [combine ~when_different_lengths [1; 2] ['a'; 'b'] = Ok [(1,'a'); (2, 'b')]]
E.g., [combine ~when_different_lengths:() [1] [] = Error ()]
Note: [combine ~when_different_lengths l1 l2] is equivalent to
[try Ok (Stdlib.List.combine l1 l2)
with Invalid_argument _ -> when_different_lengths]
The same equivalence almost holds for the other double traversors below.
The notable difference is if the functions passed as argument to the
traversors raise the [Invalid_argument _] exception. *)valcombine:when_different_lengths:'trace->'alist->'blist->(('a*'b)list,'trace)result(** [rev_combine ~when_different_lengths xs ys] is
[rev (combine ~when_different_lengths xs ys)] but more efficient. *)valrev_combine:when_different_lengths:'trace->'alist->'blist->(('a*'b)list,'trace)resultvalsplit:('a*'b)list->'alist*'blistvaliter2:when_different_lengths:'trace->('a->'b->unit)->'alist->'blist->(unit,'trace)resultvalmap2:when_different_lengths:'trace->('a->'b->'c)->'alist->'blist->('clist,'trace)resultvalrev_map2:when_different_lengths:'trace->('a->'b->'c)->'alist->'blist->('clist,'trace)resultvalfold_left2:when_different_lengths:'trace->('a->'b->'c->'a)->'a->'blist->'clist->('a,'trace)result(** This function is not tail-recursive *)valfold_right2:when_different_lengths:'trace->('a->'b->'c->'c)->'alist->'blist->'c->('c,'trace)resultvalfor_all2:when_different_lengths:'trace->('a->'b->bool)->'alist->'blist->(bool,'trace)resultvalexists2:when_different_lengths:'trace->('a->'b->bool)->'alist->'blist->(bool,'trace)result(** {3 Monad-aware variants}
The functions below are strict extensions of the standard {!Stdlib.List}
module. It is for result-, lwt- and lwt-result-aware variants. The meaning
of the suffix is as described above, in {!Lwtreslib}, and in {!Sigs.Seq}. *)(** {4 Initialisation variants}
Note that for asynchronous variants ([_s], [_es], [_p], and [_ep]), if the
length parameter is negative, then the promise is returned already
fulfilled with [Error when_different_lengths]. *)valinit_e:when_negative_length:'trace->int->(int->('a,'trace)result)->('alist,'trace)resultvalinit_s:when_negative_length:'trace->int->(int->'aLwt.t)->('alist,'trace)resultLwt.tvalinit_es:when_negative_length:'trace->int->(int->('a,'trace)resultLwt.t)->('alist,'trace)resultLwt.tvalinit_ep:when_negative_length:'error->int->(int->('a,'error)resultLwt.t)->('alist,'errorlist)resultLwt.tvalinit_p:when_negative_length:'trace->int->(int->'aLwt.t)->('alist,'trace)resultLwt.t(** {4 Query variants} *)valfind_e:('a->(bool,'trace)result)->'alist->('aoption,'trace)resultvalfind_s:('a->boolLwt.t)->'alist->'aoptionLwt.tvalfind_es:('a->(bool,'trace)resultLwt.t)->'alist->('aoption,'trace)resultLwt.tvalfilter:('a->bool)->'alist->'alist(** [rev_filter f l] is [rev (filter f l)] but more efficient. *)valrev_filter:('a->bool)->'alist->'alistvalrev_filter_some:'aoptionlist->'alistvalfilter_some:'aoptionlist->'alistvalrev_filter_ok:('a,'b)resultlist->'alistvalfilter_ok:('a,'b)resultlist->'alistvalrev_filter_error:('a,'b)resultlist->'blistvalfilter_error:('a,'b)resultlist->'blistvalrev_filter_e:('a->(bool,'trace)result)->'alist->('alist,'trace)resultvalfilter_e:('a->(bool,'trace)result)->'alist->('alist,'trace)resultvalrev_filter_s:('a->boolLwt.t)->'alist->'alistLwt.tvalfilter_s:('a->boolLwt.t)->'alist->'alistLwt.tvalrev_filter_es:('a->(bool,'trace)resultLwt.t)->'alist->('alist,'trace)resultLwt.tvalfilter_es:('a->(bool,'trace)resultLwt.t)->'alist->('alist,'trace)resultLwt.tvalfilter_ep:('a->(bool,'trace)resultLwt.t)->'alist->('alist,'tracelist)resultLwt.tvalfilter_p:('a->boolLwt.t)->'alist->'alistLwt.tvalrev_partition:('a->bool)->'alist->'alist*'alistvalpartition:('a->bool)->'alist->'alist*'alistvalrev_partition_result:('a,'b)resultlist->'alist*'blistvalpartition_result:('a,'b)resultlist->'alist*'blistvalrev_partition_e:('a->(bool,'trace)result)->'alist->('alist*'alist,'trace)resultvalpartition_e:('a->(bool,'trace)result)->'alist->('alist*'alist,'trace)resultvalrev_partition_s:('a->boolLwt.t)->'alist->('alist*'alist)Lwt.tvalpartition_s:('a->boolLwt.t)->'alist->('alist*'alist)Lwt.tvalrev_partition_es:('a->(bool,'trace)resultLwt.t)->'alist->('alist*'alist,'trace)resultLwt.tvalpartition_es:('a->(bool,'trace)resultLwt.t)->'alist->('alist*'alist,'trace)resultLwt.tvalpartition_ep:('a->(bool,'trace)resultLwt.t)->'alist->('alist*'alist,'tracelist)resultLwt.tvalpartition_p:('a->boolLwt.t)->'alist->('alist*'alist)Lwt.t(** {4 Traversal variants} *)valiter:('a->unit)->'alist->unitvaliter_e:('a->(unit,'trace)result)->'alist->(unit,'trace)resultvaliter_s:('a->unitLwt.t)->'alist->unitLwt.tvaliter_es:('a->(unit,'trace)resultLwt.t)->'alist->(unit,'trace)resultLwt.tvaliter_ep:('a->(unit,'trace)resultLwt.t)->'alist->(unit,'tracelist)resultLwt.tvaliter_p:('a->unitLwt.t)->'alist->unitLwt.tvaliteri:(int->'a->unit)->'alist->unitvaliteri_e:(int->'a->(unit,'trace)result)->'alist->(unit,'trace)resultvaliteri_s:(int->'a->unitLwt.t)->'alist->unitLwt.tvaliteri_es:(int->'a->(unit,'trace)resultLwt.t)->'alist->(unit,'trace)resultLwt.tvaliteri_ep:(int->'a->(unit,'trace)resultLwt.t)->'alist->(unit,'tracelist)resultLwt.tvaliteri_p:(int->'a->unitLwt.t)->'alist->unitLwt.tvalmap:('a->'b)->'alist->'blistvalmap_e:('a->('b,'trace)result)->'alist->('blist,'trace)resultvalmap_s:('a->'bLwt.t)->'alist->'blistLwt.tvalmap_es:('a->('b,'trace)resultLwt.t)->'alist->('blist,'trace)resultLwt.tvalmap_ep:('a->('b,'trace)resultLwt.t)->'alist->('blist,'tracelist)resultLwt.tvalmap_p:('a->'bLwt.t)->'alist->'blistLwt.tvalmapi:(int->'a->'b)->'alist->'blistvalmapi_e:(int->'a->('b,'trace)result)->'alist->('blist,'trace)resultvalmapi_s:(int->'a->'bLwt.t)->'alist->'blistLwt.tvalmapi_es:(int->'a->('b,'trace)resultLwt.t)->'alist->('blist,'trace)resultLwt.tvalmapi_ep:(int->'a->('b,'trace)resultLwt.t)->'alist->('blist,'tracelist)resultLwt.tvalmapi_p:(int->'a->'bLwt.t)->'alist->'blistLwt.tvalrev_map:('a->'b)->'alist->'blistvalrev_mapi:(int->'a->'b)->'alist->'blistvalrev_map_e:('a->('b,'trace)result)->'alist->('blist,'trace)resultvalrev_map_s:('a->'bLwt.t)->'alist->'blistLwt.tvalrev_map_es:('a->('b,'trace)resultLwt.t)->'alist->('blist,'trace)resultLwt.tvalrev_map_ep:('a->('b,'trace)resultLwt.t)->'alist->('blist,'tracelist)resultLwt.tvalrev_map_p:('a->'bLwt.t)->'alist->'blistLwt.tvalrev_mapi_e:(int->'a->('b,'trace)result)->'alist->('blist,'trace)resultvalrev_mapi_s:(int->'a->'bLwt.t)->'alist->'blistLwt.tvalrev_mapi_es:(int->'a->('b,'trace)resultLwt.t)->'alist->('blist,'trace)resultLwt.tvalrev_mapi_ep:(int->'a->('b,'trace)resultLwt.t)->'alist->('blist,'tracelist)resultLwt.tvalrev_mapi_p:(int->'a->'bLwt.t)->'alist->'blistLwt.tvalrev_filter_map:('a->'boption)->'alist->'blistvalrev_filter_map_e:('a->('boption,'trace)result)->'alist->('blist,'trace)resultvalfilter_map_e:('a->('boption,'trace)result)->'alist->('blist,'trace)resultvalrev_filter_map_s:('a->'boptionLwt.t)->'alist->'blistLwt.tvalfilter_map:('a->'boption)->'alist->'blistvalfilter_map_s:('a->'boptionLwt.t)->'alist->'blistLwt.tvalrev_filter_map_es:('a->('boption,'trace)resultLwt.t)->'alist->('blist,'trace)resultLwt.tvalfilter_map_es:('a->('boption,'trace)resultLwt.t)->'alist->('blist,'trace)resultLwt.tvalfilter_map_ep:('a->('boption,'trace)resultLwt.t)->'alist->('blist,'tracelist)resultLwt.tvalfilter_map_p:('a->'boptionLwt.t)->'alist->'blistLwt.tvalfold_left:('a->'b->'a)->'a->'blist->'avalfold_left_e:('a->'b->('a,'trace)result)->'a->'blist->('a,'trace)resultvalfold_left_s:('a->'b->'aLwt.t)->'a->'blist->'aLwt.tvalfold_left_es:('a->'b->('a,'trace)resultLwt.t)->'a->'blist->('a,'trace)resultLwt.t(** This function is not tail-recursive *)valfold_right:('a->'b->'b)->'alist->'b->'b(** This function is not tail-recursive *)valfold_right_e:('a->'b->('b,'trace)result)->'alist->'b->('b,'trace)result(** This function is not tail-recursive *)valfold_right_s:('a->'b->'bLwt.t)->'alist->'b->'bLwt.t(** This function is not tail-recursive *)valfold_right_es:('a->'b->('b,'trace)resultLwt.t)->'alist->'b->('b,'trace)resultLwt.t(** {4 Double-traversal variants}
As mentioned above, there are no [_p] and [_ep] double-traversors. Use
{!combine} (and variants) to circumvent this. *)valiter2_e:when_different_lengths:'trace->('a->'b->(unit,'trace)result)->'alist->'blist->(unit,'trace)resultvaliter2_s:when_different_lengths:'trace->('a->'b->unitLwt.t)->'alist->'blist->(unit,'trace)resultLwt.tvaliter2_es:when_different_lengths:'trace->('a->'b->(unit,'trace)resultLwt.t)->'alist->'blist->(unit,'trace)resultLwt.tvalmap2_e:when_different_lengths:'trace->('a->'b->('c,'trace)result)->'alist->'blist->('clist,'trace)resultvalmap2_s:when_different_lengths:'trace->('a->'b->'cLwt.t)->'alist->'blist->('clist,'trace)resultLwt.tvalmap2_es:when_different_lengths:'trace->('a->'b->('c,'trace)resultLwt.t)->'alist->'blist->('clist,'trace)resultLwt.tvalrev_map2_e:when_different_lengths:'trace->('a->'b->('c,'trace)result)->'alist->'blist->('clist,'trace)resultvalrev_map2_s:when_different_lengths:'trace->('a->'b->'cLwt.t)->'alist->'blist->('clist,'trace)resultLwt.tvalrev_map2_es:when_different_lengths:'trace->('a->'b->('c,'trace)resultLwt.t)->'alist->'blist->('clist,'trace)resultLwt.tvalfold_left2_e:when_different_lengths:'trace->('a->'b->'c->('a,'trace)result)->'a->'blist->'clist->('a,'trace)resultvalfold_left2_s:when_different_lengths:'trace->('a->'b->'c->'aLwt.t)->'a->'blist->'clist->('a,'trace)resultLwt.tvalfold_left2_es:when_different_lengths:'trace->('a->'b->'c->('a,'trace)resultLwt.t)->'a->'blist->'clist->('a,'trace)resultLwt.t(** This function is not tail-recursive *)valfold_right2_e:when_different_lengths:'trace->('a->'b->'c->('c,'trace)result)->'alist->'blist->'c->('c,'trace)result(** This function is not tail-recursive *)valfold_right2_s:when_different_lengths:'trace->('a->'b->'c->'cLwt.t)->'alist->'blist->'c->('c,'trace)resultLwt.t(** This function is not tail-recursive *)valfold_right2_es:when_different_lengths:'trace->('a->'b->'c->('c,'trace)resultLwt.t)->'alist->'blist->'c->('c,'trace)resultLwt.t(** {4 Scanning variants} *)valfor_all:('a->bool)->'alist->boolvalfor_all_e:('a->(bool,'trace)result)->'alist->(bool,'trace)resultvalfor_all_s:('a->boolLwt.t)->'alist->boolLwt.tvalfor_all_es:('a->(bool,'trace)resultLwt.t)->'alist->(bool,'trace)resultLwt.tvalfor_all_ep:('a->(bool,'trace)resultLwt.t)->'alist->(bool,'tracelist)resultLwt.tvalfor_all_p:('a->boolLwt.t)->'alist->boolLwt.tvalexists:('a->bool)->'alist->boolvalexists_e:('a->(bool,'trace)result)->'alist->(bool,'trace)resultvalexists_s:('a->boolLwt.t)->'alist->boolLwt.tvalexists_es:('a->(bool,'trace)resultLwt.t)->'alist->(bool,'trace)resultLwt.tvalexists_ep:('a->(bool,'trace)resultLwt.t)->'alist->(bool,'tracelist)resultLwt.tvalexists_p:('a->boolLwt.t)->'alist->boolLwt.t(** {4 Double-scanning variants}
As mentioned above, there are no [_p] and [_ep] double-scanners. Use
{!combine} (and variants) to circumvent this. *)valfor_all2_e:when_different_lengths:'trace->('a->'b->(bool,'trace)result)->'alist->'blist->(bool,'trace)resultvalfor_all2_s:when_different_lengths:'trace->('a->'b->boolLwt.t)->'alist->'blist->(bool,'trace)resultLwt.tvalfor_all2_es:when_different_lengths:'trace->('a->'b->(bool,'trace)resultLwt.t)->'alist->'blist->(bool,'trace)resultLwt.tvalexists2_e:when_different_lengths:'trace->('a->'b->(bool,'trace)result)->'alist->'blist->(bool,'trace)resultvalexists2_s:when_different_lengths:'trace->('a->'b->boolLwt.t)->'alist->'blist->(bool,'trace)resultLwt.tvalexists2_es:when_different_lengths:'trace->('a->'b->(bool,'trace)resultLwt.t)->'alist->'blist->(bool,'trace)resultLwt.t(** {3 Combine variants}
These are primarily intended to be used for preprocessing before applying
a traversor to the resulting list of pairs. They give alternatives to the
[when_different_lengths] mechanism of the immediate double-traversors
above.
In case the semantic of, say, [map2_es] was unsatisfying, one can use
[map_es] on a [combine]-preprocessed pair of lists. The different variants
of [combine] give different approaches to different-length handling. *)(** [combine_drop ll lr] is a list [l] of pairs of elements taken from the
common-length prefix of [ll] and [lr]. The suffix of whichever list is
longer (if any) is dropped.
More formally [nth l n] is:
- [None] if [n >= min (length ll) (length lr)]
- [Some (Option.get @@ nth ll n, Option.get @@ nth lr n)] otherwise
*)valcombine_drop:'alist->'blist->('a*'b)list(** [combine_with_leftovers ll lr] is a tuple [(combined, leftover)]
where [combined] is [combine_drop ll lr]
and [leftover] is either [`Left lsuffix] or [`Right rsuffix] depending on
which of [ll] or [lr] is longer. [leftover] is [None] if the two lists
have the same length. *)valcombine_with_leftovers:'alist->'blist->('a*'b)list*[`Leftof'alist|`Rightof'blist]option(** {3 compare / equal} *)valcompare:('a->'a->int)->'alist->'alist->intvalequal:('a->'a->bool)->'alist->'alist->bool(** {3 Sorting} *)valsort:('a->'a->int)->'alist->'alistvalstable_sort:('a->'a->int)->'alist->'alistvalfast_sort:('a->'a->int)->'alist->'alistvalsort_uniq:('a->'a->int)->'alist->'alist(** {3 conversion} *)valto_seq:'at->'aStdlib.Seq.tvalof_seq:'aStdlib.Seq.t->'alistend