From 73e68dae7c60ba05ac70a634c05db6630a487f35 Mon Sep 17 00:00:00 2001 From: Ben Bellick Date: Mon, 4 Dec 2023 23:01:06 -0600 Subject: [PATCH] CCList: add unfold --- src/core/CCList.ml | 5 +++++ src/core/CCList.mli | 10 ++++++++++ src/core/CCListLabels.mli | 10 ++++++++++ tests/core/t_list.ml | 10 ++++++++++ 4 files changed, 35 insertions(+) diff --git a/src/core/CCList.ml b/src/core/CCList.ml index c3c73cda..e00e1e32 100644 --- a/src/core/CCList.ml +++ b/src/core/CCList.ml @@ -281,6 +281,11 @@ let fold_flat_map_i f acc l = in aux f acc 0 [] l +let rec unfold f seed = + match f seed with + | None -> [] + | Some (v, next) -> v :: unfold f next + [@@@iflt 5.1] (* keep this because it's tailrec for < 5.1 *) diff --git a/src/core/CCList.mli b/src/core/CCList.mli index 0e159cb6..865dca79 100644 --- a/src/core/CCList.mli +++ b/src/core/CCList.mli @@ -102,6 +102,16 @@ val fold_flat_map_i : list to a list of lists that is then [flatten]'d. @since 2.8 *) +val unfold : ('seed -> ('b * 'seed) option) -> 'seed -> 'b list +(** [unfold f init] builds up a list from a seed value. + When [f] produces [Some (next_seed, value)], [value] is added to the output list and + [next_seed] is used in the next call to [f]. However, + when [f] produces [None], list production ends. + {b NOTE} if [f] never produces [None], then a {b stack overflow will occur}. Therefore, + great care must be taken to ensure that [f] will produce [None]. + @since 3.13 +*) + val count : ('a -> bool) -> 'a list -> int (** [count p l] counts how many elements of [l] satisfy predicate [p]. @since 1.5, but only diff --git a/src/core/CCListLabels.mli b/src/core/CCListLabels.mli index c0f99696..fe5d2176 100644 --- a/src/core/CCListLabels.mli +++ b/src/core/CCListLabels.mli @@ -135,6 +135,16 @@ val fold_flat_map_i : list to a list of lists that is then [flatten]'d. @since 2.8 *) +val unfold : f:('seed -> ('b * 'seed) option) -> init:'seed -> 'b list +(** [unfold ~f ~init] builds up a list from a seed value. + When [f] produces [Some (next_seed, value)], [value] is added to the output list and + [next_seed] is used in the next call to [f]. However, + when [f] produces [None], list production ends. + {b NOTE} if [f] never produces [None], then a {b stack overflow will occur}. Therefore, + great care must be taken to ensure that [f] will produce [None]. + @since 3.13 +*) + val count : f:('a -> bool) -> 'a list -> int (** [count ~f l] counts how many elements of [l] satisfy predicate [f]. @since 1.5, but only diff --git a/tests/core/t_list.ml b/tests/core/t_list.ml index 4bc6ffb1..4d2026ba 100644 --- a/tests/core/t_list.ml +++ b/tests/core/t_list.ml @@ -131,6 +131,16 @@ q = (List.rev l, flat_map (fun x -> [ x; x + 10 ]) l)) ;; +t @@ fun () -> +let f x = + if x <= 5 then + Some (2 * x, x + 1) + else + None +in +unfold f 0 = [ 0; 2; 4; 6; 8; 10 ] +;; + t @@ fun () -> init 0 (fun _ -> 0) = [];; t @@ fun () -> init 1 (fun x -> x) = [ 0 ];; t @@ fun () -> init 1000 (fun x -> x) = 0 -- 999;;