From d80d36106b07500b5d610cae488d96d4d7605029 Mon Sep 17 00:00:00 2001 From: Emmanuel Arrighi Date: Fri, 6 Feb 2026 16:22:12 +0100 Subject: [PATCH] CCSeq(chore): sync with stdlib --- src/core/CCSeq.ml | 178 +++++++++++++++++++++++++++++++-------------- src/core/CCSeq.mli | 120 ++++++++++++++++++++++++------ 2 files changed, 221 insertions(+), 77 deletions(-) diff --git a/src/core/CCSeq.ml b/src/core/CCSeq.ml index c3b8dd34..4230e319 100644 --- a/src/core/CCSeq.ml +++ b/src/core/CCSeq.ml @@ -9,10 +9,19 @@ type 'a printer = Format.formatter -> 'a -> unit include Seq let nil () = Nil + +[@@@iflt 4.11] + let cons a b () = Cons (a, b) -let empty = nil + +[@@@endif] +[@@@iflt 5.4] + let singleton x () = Cons (x, nil) +[@@@endif] +[@@@iflt 4.11] + let init n f = let rec aux i () = if i >= n then @@ -22,6 +31,8 @@ let init n f = in aux 0 +[@@@endif] + let rec _forever x () = Cons (x, _forever x) let rec _repeat n x () = @@ -37,11 +48,15 @@ let repeat ?n x = let rec forever f () = Cons (f (), forever f) +[@@@iflt 4.14] + let is_empty l = match l () with | Nil -> true | Cons _ -> false +[@@@endif] + let head_exn l = match l () with | Nil -> raise Not_found @@ -62,11 +77,15 @@ let tail l = | Nil -> None | Cons (_, l) -> Some l +[@@@iflt 4.14] + let uncons l = match l () with | Nil -> None | Cons (h, t) -> Some (h, t) +[@@@endif] + let rec equal eq l1 l2 = match l1 (), l2 () with | Nil, Nil -> true @@ -100,14 +119,9 @@ let foldi f acc res = in aux acc 0 res -let fold_lefti = foldi +[@@@iflt 4.14] -let rec iter f l = - match l () with - | Nil -> () - | Cons (x, l') -> - f x; - iter f l' +let fold_lefti = foldi let iteri f l = let rec aux f l i = @@ -151,11 +165,6 @@ let rec drop_while p l () = | Cons (x, l') when p x -> drop_while p l' () | Cons _ as res -> res -let rec map f l () = - match l () with - | Nil -> Nil - | Cons (x, l') -> Cons (f x, map f l') - let mapi f l = let rec aux f l i () = match l () with @@ -164,36 +173,55 @@ let mapi f l = in aux f l 0 -let rec fmap f (l : 'a t) () = - match l () with - | Nil -> Nil - | Cons (x, l') -> - (match f x with - | None -> fmap f l' () - | Some y -> Cons (y, fmap f l')) +[@@@endif] +[@@@iflt 5.4] -let rec filter p l () = - match l () with - | Nil -> Nil - | Cons (x, l') -> - if p x then - Cons (x, filter p l') - else - filter p l' () +let filteri f l = + let rec aux f l i () = + match l () with + | Nil -> Nil + | Cons (x, tl) -> + if f i x then + Cons (x, aux f tl (i + 1)) + else + aux f tl (i + 1) () + in + aux f l 0 + +[@@@endif] + +let fmap = filter_map + +[@@@iflt 4.11] let rec append l1 l2 () = match l1 () with | Nil -> l2 () | Cons (x, l1') -> Cons (x, append l1' l2) -let rec cycle l () = append l (cycle l) () +[@@@endif] +[@@@iflt 4.14] + +let rec cycle l = + if is_empty l then + l + else + fun () -> + append l (cycle l) () + let rec iterate f a () = Cons (a, iterate f (f a)) +[@@@endif] +[@@@iflt 4.11] + let rec unfold f acc () = match f acc with | None -> Nil | Some (x, acc') -> Cons (x, unfold f acc') +[@@@endif] +[@@@iflt 4.14] + let rec for_all p l = match l () with | Nil -> true @@ -221,6 +249,35 @@ let rec find_map f l = | None -> find_map f tl | e -> e) +[@@@endif] +[@@@iflt 5.1] + +let find_index p l = + let rec aux i l = + match l () with + | Nil -> None + | Cons (x, tl) -> + if p x then + Some i + else + aux (i + 1) tl + in + aux 0 l + +let find_mapi f l = + let rec aux i l = + match l () with + | Nil -> None + | Cons (x, tl) -> + (match f i x with + | Some _ as res -> res + | None -> aux (i + 1) tl) + in + aux 0 l + +[@@@endif] +[@@@iflt 5.1] + let rec scan f acc res () = Cons ( acc, @@ -229,18 +286,13 @@ let rec scan f acc res () = | Nil -> Nil | Cons (s, cont) -> scan f (f acc s) cont () ) -let rec flat_map f l () = - match l () with - | Nil -> Nil - | Cons (x, l') -> _flat_map_app f (f x) l' () - -and _flat_map_app f l l' () = - match l () with - | Nil -> flat_map f l' () - | Cons (x, tl) -> Cons (x, _flat_map_app f tl l') +[@@@endif] +[@@@iflt 4.13] let concat_map = flat_map +[@@@endif] + let product_with f l1 l2 = let rec _next_left h1 tl1 h2 tl2 () = match tl1 () with @@ -264,6 +316,8 @@ let product_with f l1 l2 = in _next_left [] l1 [] l2 +[@@@iflt 4.14] + let map_product = product_with let product l1 l2 = product_with (fun x y -> x, y) l1 l2 @@ -273,6 +327,8 @@ let rec group eq l () = | Cons (x, l') -> Cons (cons x (take_while (eq x) l'), group eq (drop_while (eq x) l')) +[@@@endif] + let rec _uniq eq prev l () = match prev, l () with | _, Nil -> Nil @@ -285,16 +341,13 @@ let rec _uniq eq prev l () = let uniq eq l = _uniq eq None l -let rec filter_map f l () = - match l () with - | Nil -> Nil - | Cons (x, l') -> - (match f x with - | None -> filter_map f l' () - | Some y -> Cons (y, filter_map f l')) +[@@@iflt 4.13] -let flatten l = flat_map (fun x -> x) l -let concat = flatten +let concat l = flat_map (fun x -> x) l + +[@@@endif] + +let flatten = concat let range i j = let rec aux i j () = @@ -317,12 +370,18 @@ let ( --^ ) i j = else range i (j + 1) -let rec fold2 f acc l1 l2 = +[@@@iflt 4.14] + +let rec fold_left2 f acc l1 l2 = match l1 (), l2 () with | Nil, _ | _, Nil -> acc - | Cons (x1, l1'), Cons (x2, l2') -> fold2 f (f acc x1 x2) l1' l2' + | Cons (x1, l1'), Cons (x2, l2') -> fold_left2 f (f acc x1 x2) l1' l2' -let fold_left2 = fold2 +[@@@endif] + +let fold2 = fold_left2 + +[@@@iflt 4.14] let rec map2 f l1 l2 () = match l1 (), l2 () with @@ -346,17 +405,21 @@ let rec exists2 f l1 l2 = | Nil, _ | _, Nil -> false | Cons (x1, l1'), Cons (x2, l2') -> f x1 x2 || exists2 f l1' l2' -let rec merge cmp l1 l2 () = +let rec sorted_merge cmp l1 l2 () = match l1 (), l2 () with | Nil, tl2 -> tl2 | tl1, Nil -> tl1 | Cons (x1, l1'), Cons (x2, l2') -> if cmp x1 x2 < 0 then - Cons (x1, merge cmp l1' l2) + Cons (x1, sorted_merge cmp l1' l2) else - Cons (x2, merge cmp l1 l2') + Cons (x2, sorted_merge cmp l1 l2') -let sorted_merge = merge +[@@@endif] + +let merge = sorted_merge + +[@@@iflt 4.14] let rec zip a b () = match a (), b () with @@ -377,6 +440,8 @@ let unzip l = let split = unzip +[@@@endif] + let zip_i seq = let rec loop i seq () = match seq () with @@ -387,7 +452,6 @@ let zip_i seq = (** {2 Implementations} *) -let return x () = Cons (x, nil) let pure = return let ( >>= ) xs f = flat_map f xs let ( >|= ) xs f = map f xs @@ -530,11 +594,15 @@ let rec memoize f = (** {2 Fair Combinations} *) +[@@@iflt 4.14] + let rec interleave a b () = match a () with | Nil -> b () | Cons (x, tail) -> Cons (x, interleave b tail) +[@@@endif] + let rec fair_flat_map f a () = match a () with | Nil -> Nil diff --git a/src/core/CCSeq.mli b/src/core/CCSeq.mli index a26fa1a1..cea1951f 100644 --- a/src/core/CCSeq.mli +++ b/src/core/CCSeq.mli @@ -17,38 +17,60 @@ include module type of Seq (** @inline *) val nil : 'a t -val empty : 'a t + +[@@@iflt 4.11] + val cons : 'a -> 'a t -> 'a t + +[@@@endif] +[@@@iflt 5.4] + val singleton : 'a -> 'a t +[@@@endif] +[@@@iflt 4.14] + val init : int -> (int -> 'a) -> 'a t (** [init n f] corresponds to the sequence [f 0; f 1; ...; f (n-1)]. @raise Invalid_argument if n is negative. @since 3.10 *) +[@@@endif] + val repeat : ?n:int -> 'a -> 'a t (** [repeat ~n x] repeats [x] [n] times then stops. If [n] is omitted, then [x] is repeated forever. *) +[@@@iflt 4.14] + val forever : (unit -> 'a) -> 'a t (** [forever f] corresponds to the infinite sequence containing all the [f ()]. @since 3.10 *) val cycle : 'a t -> 'a t -(** Cycle through the iterator infinitely. The iterator shouldn't be empty. *) +(** Cycle through the sequence infinitely. The sequence should be persistent. + @since NEXT_RELEASE the sequence can be empty, in this case cycle return an empty sequence. *) val iterate : ('a -> 'a) -> 'a -> 'a t (** [iterate f a] corresponds to the infinite sequence containing [a], [f a], [f (f a)], ... @since 3.10 *) +[@@@endif] +[@@@iflt 4.11] + val unfold : ('b -> ('a * 'b) option) -> 'b -> 'a t (** [unfold f acc] calls [f acc] and: - if [f acc = Some (x, acc')], yield [x], continue with [unfold f acc']. - if [f acc = None], stops. *) +[@@@endif] +[@@@iflt 4.14] + val is_empty : 'a t -> bool -(** [is_empty xs] checks in the sequence [xs] is empty *) +(** [is_empty xs] checks in the sequence [xs] is empty. [is_empty] acces the first element of the sequence, this can causes issue if the sequence is ephemeral. *) + +[@@@endif] val head : 'a t -> 'a option (** Head of the list. *) @@ -64,10 +86,14 @@ val tail_exn : 'a t -> 'a t (** Unsafe version of {!tail}. @raise Not_found if the list is empty. *) +[@@@iflt 4.14] + val uncons : 'a t -> ('a * 'a t) option (** [uncons xs] return [None] if [xs] is empty other @since 3.10 *) +[@@@endif] + val equal : 'a equal -> 'a t equal (** Equality step by step. Eager. *) @@ -86,12 +112,12 @@ val foldi : ('a -> int -> 'b -> 'a) -> 'a -> 'b t -> 'a 0) and [x] is the element of the sequence. @since 3.10 *) +[@@@iflt 4.14] + val fold_lefti : ('a -> int -> 'b -> 'a) -> 'a -> 'b t -> 'a (** Alias of {!foldi}. @since 3.10 *) -val iter : ('a -> unit) -> 'a t -> unit - val iteri : (int -> 'a -> unit) -> 'a t -> unit (** Iterate with index (starts at 0). *) @@ -104,19 +130,33 @@ val take : int -> 'a t -> 'a t val take_while : ('a -> bool) -> 'a t -> 'a t val drop : int -> 'a t -> 'a t val drop_while : ('a -> bool) -> 'a t -> 'a t -val map : ('a -> 'b) -> 'a t -> 'b t val mapi : (int -> 'a -> 'b) -> 'a t -> 'b t (** Map with index (starts at 0). *) +[@@@endif] +[@@@iflt 5.4] + +val filteri : (int -> 'a -> bool) -> 'a t -> 'a t +(** Similar to {!filter} but the predicate takes aditionally the index of the elements. *) + +[@@@endif] + val fmap : ('a -> 'b option) -> 'a t -> 'b t -val filter : ('a -> bool) -> 'a t -> 'a t +(** Alias of {!filter_map}. *) + +[@@@iflt 4.11] + val append : 'a t -> 'a t -> 'a t +[@@@endif] + val product_with : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t (** Fair product of two (possibly infinite) lists into a new list. Lazy. The first parameter is used to combine each pair of elements. *) +[@@@iflt 4.14] + val map_product : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t (** Alias of {!product_with}. @since 3.10 *) @@ -129,11 +169,15 @@ val group : 'a equal -> 'a t -> 'a t t For instance [group (=) [1;1;1;2;2;3;3;1]] yields [[1;1;1]; [2;2]; [3;3]; [1]]. *) +[@@@endif] + val uniq : 'a equal -> 'a t -> 'a t (** [uniq eq l] returns [l] but removes consecutive duplicates. Lazy. In other words, if several values that are equal follow one another, only the first of them is kept. *) +[@@@iflt 4.14] + val for_all : ('a -> bool) -> 'a t -> bool (** [for_all p [a1; ...; an]] checks if all elements of the sequence satisfy the predicate [p]. That is, it returns [(p a1) && ... && (p an)] for a @@ -158,23 +202,37 @@ val find_map : ('a -> 'b option) -> 'a t -> 'b option [f ai = Some _] and return [None] otherwise. @since 3.10 *) +[@@@endif] +[@@@iflt 5.1] + +val find_index : ('a -> bool) -> 'a t -> int option +(** [find_index p xs] returns [Some i], where [i] is the index of the first value of [xs] satisfying [p]. It returns [None] if no value of [xs] satifies [p]. *) + +val find_mapi : (int -> 'a -> 'b option) -> 'a t -> 'b option +(** Similar to {!find_map} but the predicate take aditionnaly the index of the element. *) + +[@@@endif] +[@@@iflt 4.14] + val scan : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a t (** [scan f init xs] is the sequence containing the intermediate result of [fold f init xs]. @since 3.10 *) -val flat_map : ('a -> 'b t) -> 'a t -> 'b t +[@@@endif] +[@@@iflt 4.13] val concat_map : ('a -> 'b t) -> 'a t -> 'b t (** Alias of {!flat_map} @since 3.10 *) -val filter_map : ('a -> 'b option) -> 'a t -> 'b t -val flatten : 'a t t -> 'a t - val concat : 'a t t -> 'a t -(** Alias of {!flatten}. - @since 3.10 *) +(** @since 3.10 *) + +[@@@endif] + +val flatten : 'a t t -> 'a t +(** Alias of {!concat} *) val range : int -> int -> int t @@ -187,12 +245,18 @@ val ( --^ ) : int -> int -> int t (** {2 Operations on two Collections} *) -val fold2 : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> 'a t -> 'b t -> 'acc -(** Fold on two collections at once. Stop as soon as one of them ends. *) +[@@@iflt 4.14] val fold_left2 : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> 'a t -> 'b t -> 'acc -(** Alias for {!fold2}. - @since 3.10 *) +(** Fold on two collections at once. Stop as soon as one of them ends. +@since 3.10 *) + +[@@@endif] + +val fold2 : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> 'a t -> 'b t -> 'acc +(** Alias for {!fold_left2}. *) + +[@@@iflt 4.14] val map2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t (** Map on two collections at once. Stop as soon as one of the @@ -204,12 +268,19 @@ val iter2 : ('a -> 'b -> unit) -> 'a t -> 'b t -> unit val for_all2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool val exists2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool -val merge : 'a ord -> 'a t -> 'a t -> 'a t -(** Merge two sorted iterators into a sorted iterator. *) +[@@@endif] +[@@@iflt 4.14] val sorted_merge : 'a ord -> 'a t -> 'a t -> 'a t -(** Alias of {!merge}. - @since 3.10 *) +(** Merge two sorted iterators into a sorted iterator. + @since 3.10 *) + +[@@@endif] + +val merge : 'a ord -> 'a t -> 'a t -> 'a t +(** Alias of {!sorted_merge}. *) + +[@@@iflt 4.14] val zip : 'a t -> 'b t -> ('a * 'b) t (** Combine elements pairwise. Stop as soon as one of the lists stops. *) @@ -221,6 +292,8 @@ val split : ('a * 'b) t -> 'a t * 'b t (** Alias of {!unzip}. @since 3.10 *) +[@@@endif] + val zip_i : 'a t -> (int * 'a) t (** [zip_i seq] zips the index of each element with the element itself. @since 3.8 @@ -241,9 +314,13 @@ val memoize : 'a t -> 'a t (** {2 Fair Combinations} *) +[@@@iflt 4.14] + val interleave : 'a t -> 'a t -> 'a t (** Fair interleaving of both streams. *) +[@@@endif] + val fair_flat_map : ('a -> 'b t) -> 'a t -> 'b t (** Fair version of {!flat_map}. *) @@ -252,7 +329,6 @@ val fair_app : ('a -> 'b) t -> 'a t -> 'b t (** {2 Implementations} *) -val return : 'a -> 'a t val pure : 'a -> 'a t val ( >>= ) : 'a t -> ('a -> 'b t) -> 'b t val ( >|= ) : 'a t -> ('a -> 'b) -> 'b t