package octez-proto-libs
Install
dune-project
Dependency
Authors
Maintainers
Sources
sha256=ddfb5076eeb0b32ac21c1eed44e8fc86a6743ef18ab23fff02d36e365bb73d61
sha512=d22a827df5146e0aa274df48bc2150b098177ff7e5eab52c6109e867eb0a1f0ec63e6bfbb0e3645a6c2112de3877c91a17df32ccbff301891ce4ba630c997a65
doc/octez-proto-libs.protocol-environment/Tezos_protocol_environment/V4/Make/List/index.html
Module Make.ListSource
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.
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
_esuffix is for result-aware traversors ("e" stands for "error"),_sand_pare for Lwt-aware, and_esand_epare for Lwt-result-aware. _e,_s, and_estraversors are fail-early: they stop traversal as soon as a failure (ErrororFail) occurs;_pand_eptraversors are best-effort: they only resolve once all of the intermediate promises have, even if a failure occurs.
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 alternatives that handles the error differently: combine_drop, combine_with_leftovers. Finally, the rev_combine is provided to allow to avoid multiple-reversing.
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 though the arguments have different lengths.
Trivial values
in-monad, preallocated nil
val nil_e : ('a list, 'trace) Pervasives.resultnil_e is Ok []
val nil_s : 'a list Lwt.tnil_s is Lwt.return_nil
val nil_es : ('a list, 'trace) Pervasives.result Lwt.tnil_es is Lwt.return (Ok [])
Safe wrappers
Shadowing unsafe functions to avoid all exceptions.
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.
tl xs is the tail of the list (the whole list except the first element) or None if the list is empty.
nth xs n is the nth element of the list or None if the list has fewer than n elements.
nth xs 0 = hd xs
nth_opt is an alias for nth provided for backwards compatibility.
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.
last_opt xs is the last element of the list xs or None if the list xs is empty.
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.
find_opt is an alias for find provided for backwards compatibility.
mem ~equal a l is true iff there is an element e of l such that equal a e.
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.
assoc_opt is an alias for assoc provided for backwards compatibility.
assq k kvs is the same as assoc ~equal:Stdlib.( == ) k kvs: it uses the physical equality.
assq_opt is an alias for assq provided for backwards compatibility.
mem_assoc ~equal k l is equivalent to Option.is_some @@ assoc ~equal k l.
remove_assoc ~equal k l is l without the first element (k', _) such that equal k k'.
remove_assoq k l is remove_assoc ~equal:Stdlib.( == ) k l.
Initialisation
val init :
when_negative_length:'trace ->
int ->
(int -> 'a) ->
('a list, 'trace) Pervasives.resultinit ~when_negative_length n f is Error when_negative_length if n is strictly negative and Ok (Stdlib.List.init n f) otherwise.
Basic traversal
Double-list traversals
These safe-wrappers take an explicit value to handle the case of lists of unequal length.
val combine :
when_different_lengths:'trace ->
'a list ->
'b list ->
(('a * 'b) list, 'trace) Pervasives.resultcombine ~when_different_lengths l1 l2 is either
Error when_different_lengthsifList.length l1 <> List.length l2- a list of pairs of elements from
l1andl2
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.
val rev_combine :
when_different_lengths:'trace ->
'a list ->
'b list ->
(('a * 'b) list, 'trace) Pervasives.resultrev_combine ~when_different_lengths xs ys is rev (combine ~when_different_lengths xs ys) but more efficient.
val iter2 :
when_different_lengths:'trace ->
('a -> 'b -> unit) ->
'a list ->
'b list ->
(unit, 'trace) Pervasives.resultval map2 :
when_different_lengths:'trace ->
('a -> 'b -> 'c) ->
'a list ->
'b list ->
('c list, 'trace) Pervasives.resultval rev_map2 :
when_different_lengths:'trace ->
('a -> 'b -> 'c) ->
'a list ->
'b list ->
('c list, 'trace) Pervasives.resultval fold_left2 :
when_different_lengths:'trace ->
('a -> 'b -> 'c -> 'a) ->
'a ->
'b list ->
'c list ->
('a, 'trace) Pervasives.resultval fold_right2 :
when_different_lengths:'trace ->
('a -> 'b -> 'c -> 'c) ->
'a list ->
'b list ->
'c ->
('c, 'trace) Pervasives.resultThis function is not tail-recursive
fold_left_map f a xs is a combination of fold_left and map that maps over all elements of xs and threads an accumulator with initial value a through calls to f.
val for_all2 :
when_different_lengths:'trace ->
('a -> 'b -> bool) ->
'a list ->
'b list ->
(bool, 'trace) Pervasives.resultval exists2 :
when_different_lengths:'trace ->
('a -> 'b -> bool) ->
'a list ->
'b list ->
(bool, 'trace) Pervasives.resultMonad-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.
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.
val init_e :
when_negative_length:'trace ->
int ->
(int -> ('a, 'trace) Pervasives.result) ->
('a list, 'trace) Pervasives.resultval init_s :
when_negative_length:'trace ->
int ->
(int -> 'a Lwt.t) ->
('a list, 'trace) Pervasives.result Lwt.tval init_es :
when_negative_length:'trace ->
int ->
(int -> ('a, 'trace) Pervasives.result Lwt.t) ->
('a list, 'trace) Pervasives.result Lwt.tval init_p :
when_negative_length:'trace ->
int ->
(int -> 'a Lwt.t) ->
('a list, 'trace) Pervasives.result Lwt.tQuery variants
val find_e :
('a -> (bool, 'trace) Pervasives.result) ->
'a list ->
('a option, 'trace) Pervasives.resultval find_es :
('a -> (bool, 'trace) Pervasives.result Lwt.t) ->
'a list ->
('a option, 'trace) Pervasives.result Lwt.trev_filter f l is rev (filter f l) but more efficient.
val rev_filter_ok : ('a, 'b) Pervasives.result list -> 'a listval filter_ok : ('a, 'b) Pervasives.result list -> 'a listval rev_filter_error : ('a, 'b) Pervasives.result list -> 'b listval filter_error : ('a, 'b) Pervasives.result list -> 'b listval rev_filter_e :
('a -> (bool, 'trace) Pervasives.result) ->
'a list ->
('a list, 'trace) Pervasives.resultval filter_e :
('a -> (bool, 'trace) Pervasives.result) ->
'a list ->
('a list, 'trace) Pervasives.resultval rev_filter_es :
('a -> (bool, 'trace) Pervasives.result Lwt.t) ->
'a list ->
('a list, 'trace) Pervasives.result Lwt.tval filter_es :
('a -> (bool, 'trace) Pervasives.result Lwt.t) ->
'a list ->
('a list, 'trace) Pervasives.result Lwt.tval rev_partition_result : ('a, 'b) Pervasives.result list -> 'a list * 'b listval partition_result : ('a, 'b) Pervasives.result list -> 'a list * 'b listval rev_partition_e :
('a -> (bool, 'trace) Pervasives.result) ->
'a list ->
('a list * 'a list, 'trace) Pervasives.resultval partition_e :
('a -> (bool, 'trace) Pervasives.result) ->
'a list ->
('a list * 'a list, 'trace) Pervasives.resultval rev_partition_es :
('a -> (bool, 'trace) Pervasives.result Lwt.t) ->
'a list ->
('a list * 'a list, 'trace) Pervasives.result Lwt.tval partition_es :
('a -> (bool, 'trace) Pervasives.result Lwt.t) ->
'a list ->
('a list * 'a list, 'trace) Pervasives.result Lwt.tval iter_e :
('a -> (unit, 'trace) Pervasives.result) ->
'a list ->
(unit, 'trace) Pervasives.resultval iter_es :
('a -> (unit, 'trace) Pervasives.result Lwt.t) ->
'a list ->
(unit, 'trace) Pervasives.result Lwt.tval iteri_e :
(int -> 'a -> (unit, 'trace) Pervasives.result) ->
'a list ->
(unit, 'trace) Pervasives.resultval iteri_es :
(int -> 'a -> (unit, 'trace) Pervasives.result Lwt.t) ->
'a list ->
(unit, 'trace) Pervasives.result Lwt.tval map_e :
('a -> ('b, 'trace) Pervasives.result) ->
'a list ->
('b list, 'trace) Pervasives.resultval map_es :
('a -> ('b, 'trace) Pervasives.result Lwt.t) ->
'a list ->
('b list, 'trace) Pervasives.result Lwt.tval mapi_e :
(int -> 'a -> ('b, 'trace) Pervasives.result) ->
'a list ->
('b list, 'trace) Pervasives.resultval mapi_es :
(int -> 'a -> ('b, 'trace) Pervasives.result Lwt.t) ->
'a list ->
('b list, 'trace) Pervasives.result Lwt.tval rev_map_e :
('a -> ('b, 'trace) Pervasives.result) ->
'a list ->
('b list, 'trace) Pervasives.resultval rev_map_es :
('a -> ('b, 'trace) Pervasives.result Lwt.t) ->
'a list ->
('b list, 'trace) Pervasives.result Lwt.tval rev_mapi_e :
(int -> 'a -> ('b, 'trace) Pervasives.result) ->
'a list ->
('b list, 'trace) Pervasives.resultval rev_mapi_es :
(int -> 'a -> ('b, 'trace) Pervasives.result Lwt.t) ->
'a list ->
('b list, 'trace) Pervasives.result Lwt.tval rev_filter_map_e :
('a -> ('b option, 'trace) Pervasives.result) ->
'a list ->
('b list, 'trace) Pervasives.resultval filter_map_e :
('a -> ('b option, 'trace) Pervasives.result) ->
'a list ->
('b list, 'trace) Pervasives.resultval rev_filter_map_es :
('a -> ('b option, 'trace) Pervasives.result Lwt.t) ->
'a list ->
('b list, 'trace) Pervasives.result Lwt.tval filter_map_es :
('a -> ('b option, 'trace) Pervasives.result Lwt.t) ->
'a list ->
('b list, 'trace) Pervasives.result Lwt.tval concat_map_e :
('a -> ('b list, 'error) Pervasives.result) ->
'a list ->
('b list, 'error) Pervasives.resultval concat_map_es :
('a -> ('b list, 'error) Pervasives.result Lwt.t) ->
'a list ->
('b list, 'error) Pervasives.result Lwt.tval fold_left_e :
('a -> 'b -> ('a, 'trace) Pervasives.result) ->
'a ->
'b list ->
('a, 'trace) Pervasives.resultval fold_left_es :
('a -> 'b -> ('a, 'trace) Pervasives.result Lwt.t) ->
'a ->
'b list ->
('a, 'trace) Pervasives.result Lwt.tval fold_left_map_e :
('a -> 'b -> ('a * 'c, 'trace) Pervasives.result) ->
'a ->
'b list ->
('a * 'c list, 'trace) Pervasives.resultfold_left_map_e f a xs is a combination of fold_left_e and map_e that maps over all elements of xs and threads an accumulator with initial value a through calls to f. The list is traversed from left to right and the first encountered error is returned.
fold_left_map_s f a xs is a combination of fold_left_s and map_s that maps over all elements of xs and threads an accumulator with initial value a through calls to f.
val fold_left_map_es :
('a -> 'b -> ('a * 'c, 'trace) Pervasives.result Lwt.t) ->
'a ->
'b list ->
('a * 'c list, 'trace) Pervasives.result Lwt.tfold_left_map_es f a xs is a combination of fold_left_es and map_es that maps over all elements of xs and threads an accumulator with initial value a through calls to f. The list is traversed from left to right and the first encountered error is returned.
val fold_left_i_e :
(int -> 'a -> 'b -> ('a, 'trace) Pervasives.result) ->
'a ->
'b list ->
('a, 'trace) Pervasives.resultval fold_left_i_es :
(int -> 'a -> 'b -> ('a, 'trace) Pervasives.result Lwt.t) ->
'a ->
'b list ->
('a, 'trace) Pervasives.result Lwt.tval fold_right_e :
('a -> 'b -> ('b, 'trace) Pervasives.result) ->
'a list ->
'b ->
('b, 'trace) Pervasives.resultThis function is not tail-recursive
This function is not tail-recursive
val fold_right_es :
('a -> 'b -> ('b, 'trace) Pervasives.result Lwt.t) ->
'a list ->
'b ->
('b, 'trace) Pervasives.result Lwt.tThis function is not tail-recursive
Double-traversal variants
As mentioned above, there are no _p and _ep double-traversors. Use combine (and variants) to circumvent this.
val iter2_e :
when_different_lengths:'trace ->
('a -> 'b -> (unit, 'trace) Pervasives.result) ->
'a list ->
'b list ->
(unit, 'trace) Pervasives.resultval iter2_s :
when_different_lengths:'trace ->
('a -> 'b -> unit Lwt.t) ->
'a list ->
'b list ->
(unit, 'trace) Pervasives.result Lwt.tval iter2_es :
when_different_lengths:'trace ->
('a -> 'b -> (unit, 'trace) Pervasives.result Lwt.t) ->
'a list ->
'b list ->
(unit, 'trace) Pervasives.result Lwt.tval map2_e :
when_different_lengths:'trace ->
('a -> 'b -> ('c, 'trace) Pervasives.result) ->
'a list ->
'b list ->
('c list, 'trace) Pervasives.resultval map2_s :
when_different_lengths:'trace ->
('a -> 'b -> 'c Lwt.t) ->
'a list ->
'b list ->
('c list, 'trace) Pervasives.result Lwt.tval map2_es :
when_different_lengths:'trace ->
('a -> 'b -> ('c, 'trace) Pervasives.result Lwt.t) ->
'a list ->
'b list ->
('c list, 'trace) Pervasives.result Lwt.tval rev_map2_e :
when_different_lengths:'trace ->
('a -> 'b -> ('c, 'trace) Pervasives.result) ->
'a list ->
'b list ->
('c list, 'trace) Pervasives.resultval rev_map2_s :
when_different_lengths:'trace ->
('a -> 'b -> 'c Lwt.t) ->
'a list ->
'b list ->
('c list, 'trace) Pervasives.result Lwt.tval rev_map2_es :
when_different_lengths:'trace ->
('a -> 'b -> ('c, 'trace) Pervasives.result Lwt.t) ->
'a list ->
'b list ->
('c list, 'trace) Pervasives.result Lwt.tval fold_left2_e :
when_different_lengths:'trace ->
('a -> 'b -> 'c -> ('a, 'trace) Pervasives.result) ->
'a ->
'b list ->
'c list ->
('a, 'trace) Pervasives.resultval fold_left2_s :
when_different_lengths:'trace ->
('a -> 'b -> 'c -> 'a Lwt.t) ->
'a ->
'b list ->
'c list ->
('a, 'trace) Pervasives.result Lwt.tval fold_left2_es :
when_different_lengths:'trace ->
('a -> 'b -> 'c -> ('a, 'trace) Pervasives.result Lwt.t) ->
'a ->
'b list ->
'c list ->
('a, 'trace) Pervasives.result Lwt.tval fold_right2_e :
when_different_lengths:'trace ->
('a -> 'b -> 'c -> ('c, 'trace) Pervasives.result) ->
'a list ->
'b list ->
'c ->
('c, 'trace) Pervasives.resultThis function is not tail-recursive
val fold_right2_s :
when_different_lengths:'trace ->
('a -> 'b -> 'c -> 'c Lwt.t) ->
'a list ->
'b list ->
'c ->
('c, 'trace) Pervasives.result Lwt.tThis function is not tail-recursive
val fold_right2_es :
when_different_lengths:'trace ->
('a -> 'b -> 'c -> ('c, 'trace) Pervasives.result Lwt.t) ->
'a list ->
'b list ->
'c ->
('c, 'trace) Pervasives.result Lwt.tThis function is not tail-recursive
Scanning variants
val for_all_e :
('a -> (bool, 'trace) Pervasives.result) ->
'a list ->
(bool, 'trace) Pervasives.resultval for_all_es :
('a -> (bool, 'trace) Pervasives.result Lwt.t) ->
'a list ->
(bool, 'trace) Pervasives.result Lwt.tval exists_e :
('a -> (bool, 'trace) Pervasives.result) ->
'a list ->
(bool, 'trace) Pervasives.resultval exists_es :
('a -> (bool, 'trace) Pervasives.result Lwt.t) ->
'a list ->
(bool, 'trace) Pervasives.result Lwt.tDouble-scanning variants
As mentioned above, there are no _p and _ep double-scanners. Use combine (and variants) to circumvent this.
val for_all2_e :
when_different_lengths:'trace ->
('a -> 'b -> (bool, 'trace) Pervasives.result) ->
'a list ->
'b list ->
(bool, 'trace) Pervasives.resultval for_all2_s :
when_different_lengths:'trace ->
('a -> 'b -> bool Lwt.t) ->
'a list ->
'b list ->
(bool, 'trace) Pervasives.result Lwt.tval for_all2_es :
when_different_lengths:'trace ->
('a -> 'b -> (bool, 'trace) Pervasives.result Lwt.t) ->
'a list ->
'b list ->
(bool, 'trace) Pervasives.result Lwt.tval exists2_e :
when_different_lengths:'trace ->
('a -> 'b -> (bool, 'trace) Pervasives.result) ->
'a list ->
'b list ->
(bool, 'trace) Pervasives.resultval exists2_s :
when_different_lengths:'trace ->
('a -> 'b -> bool Lwt.t) ->
'a list ->
'b list ->
(bool, 'trace) Pervasives.result Lwt.tval exists2_es :
when_different_lengths:'trace ->
('a -> 'b -> (bool, 'trace) Pervasives.result Lwt.t) ->
'a list ->
'b list ->
(bool, 'trace) Pervasives.result Lwt.tCombine 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:
Noneifn >= min (length ll) (length lr)Some (Option.get @@ nth ll n, Option.get @@ nth lr n)otherwise
A type like result but which is symmetric
val combine_with_leftovers :
'a list ->
'b list ->
('a * 'b) list * ('a, 'b) left_or_right_list optioncombine_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.
compare / equal
Sorting
conversion
val to_seq : 'a list -> 'a Seq.tval of_seq : 'a Seq.t -> 'a listval init_ep :
when_negative_length:'error ->
int ->
(int -> ('a, 'error Error_monad.trace) Pervasives.result Lwt.t) ->
('a list, 'error Error_monad.trace) Pervasives.result Lwt.tval filter_ep :
('a -> (bool, 'error Error_monad.trace) Pervasives.result Lwt.t) ->
'a list ->
('a list, 'error Error_monad.trace) Pervasives.result Lwt.tval partition_ep :
('a -> (bool, 'error Error_monad.trace) Pervasives.result Lwt.t) ->
'a list ->
('a list * 'a list, 'error Error_monad.trace) Pervasives.result Lwt.tval iter_ep :
('a -> (unit, 'error Error_monad.trace) Pervasives.result Lwt.t) ->
'a list ->
(unit, 'error Error_monad.trace) Pervasives.result Lwt.tval iteri_ep :
(int -> 'a -> (unit, 'error Error_monad.trace) Pervasives.result Lwt.t) ->
'a list ->
(unit, 'error Error_monad.trace) Pervasives.result Lwt.tval map_ep :
('a -> ('b, 'error Error_monad.trace) Pervasives.result Lwt.t) ->
'a list ->
('b list, 'error Error_monad.trace) Pervasives.result Lwt.tval mapi_ep :
(int -> 'a -> ('b, 'error Error_monad.trace) Pervasives.result Lwt.t) ->
'a list ->
('b list, 'error Error_monad.trace) Pervasives.result Lwt.tval rev_map_ep :
('a -> ('b, 'error Error_monad.trace) Pervasives.result Lwt.t) ->
'a list ->
('b list, 'error Error_monad.trace) Pervasives.result Lwt.tval rev_mapi_ep :
(int -> 'a -> ('b, 'error Error_monad.trace) Pervasives.result Lwt.t) ->
'a list ->
('b list, 'error Error_monad.trace) Pervasives.result Lwt.tval filter_map_ep :
('a -> ('b option, 'error Error_monad.trace) Pervasives.result Lwt.t) ->
'a list ->
('b list, 'error Error_monad.trace) Pervasives.result Lwt.tval concat_map_ep :
('a -> ('b list, 'error Error_monad.trace) Pervasives.result Lwt.t) ->
'a list ->
('b list, 'error Error_monad.trace) Pervasives.result Lwt.tval for_all_ep :
('a -> (bool, 'error Error_monad.trace) Pervasives.result Lwt.t) ->
'a list ->
(bool, 'error Error_monad.trace) Pervasives.result Lwt.tval exists_ep :
('a -> (bool, 'error Error_monad.trace) Pervasives.result Lwt.t) ->
'a list ->
(bool, 'error Error_monad.trace) Pervasives.result Lwt.t