Add Iter.map_while

This commit is contained in:
Olivier Nicole 2023-11-15 11:29:12 +01:00 committed by Simon Cruanes
parent 67c46b6ce4
commit 4bf00eabad
5 changed files with 39 additions and 1 deletions

View file

@ -17,6 +17,7 @@ depends: [
"ounit2" {with-test} "ounit2" {with-test}
"mdx" {with-test & >= "1.3" } "mdx" {with-test & >= "1.3" }
"odoc" {with-doc} "odoc" {with-doc}
"containers" {with-test}
] ]
tags: [ "iter" "iterator" "iter" "fold" ] tags: [ "iter" "iterator" "iter" "fold" ]
homepage: "https://github.com/c-cube/iter/" homepage: "https://github.com/c-cube/iter/"

View file

@ -658,6 +658,16 @@ let take_while p seq k =
exception ExitFoldWhile exception ExitFoldWhile
let map_while f seq k =
let exception ExitMapWhile in
let consume x =
match f x with
| `Yield y -> k y
| `Return y -> k y; raise_notrace ExitMapWhile
| `Stop -> raise_notrace ExitMapWhile
in
try seq consume with ExitMapWhile -> ()
let fold_while f s seq = let fold_while f s seq =
let state = ref s in let state = ref s in
let consume x = let consume x =

View file

@ -487,6 +487,17 @@ val take_while : ('a -> bool) -> 'a t -> 'a t
Will work on an infinite iterator [s] if the predicate is false for at Will work on an infinite iterator [s] if the predicate is false for at
least one element of [s]. *) least one element of [s]. *)
val map_while : ('a -> [ `Yield of 'b | `Return of 'b | `Stop ]) -> 'a t -> 'b t
(** Maps over elements of the iterator, stopping early if the mapped function
returns [`Stop] or [`Return x]. At each iteration:
{ul
{- If [f] returns [`Yield y], [y] is added to the sequence and the
iteration continues.}
{- If [f] returns [`Stop], nothing is added to the sequence and the
iteration stops.}
{- If [f] returns [`Return y], [y] is added to the sequence and the
iteration stops.}} *)
val fold_while : ('a -> 'b -> 'a * [ `Stop | `Continue ]) -> 'a -> 'b t -> 'a val fold_while : ('a -> 'b -> 'a * [ `Stop | `Continue ]) -> 'a -> 'b t -> 'a
(** Folds over elements of the iterator, stopping early if the accumulator (** Folds over elements of the iterator, stopping early if the accumulator
returns [('a, `Stop)] returns [('a, `Stop)]

View file

@ -1,4 +1,4 @@
(tests (tests
(names t_iter) (names t_iter)
(libraries iter qcheck-core qcheck-core.runner ounit2)) (libraries iter qcheck-core qcheck-core.runner ounit2 containers))

View file

@ -237,6 +237,22 @@ let () =
OUnit.assert_equal 2 n; OUnit.assert_equal 2 n;
() ()
let () =
OUnit.assert_equal
~cmp:(CCList.equal Int.equal)
(1 -- 10
|> map_while (fun x -> if x = 7 then `Return (x + 1) else `Yield (x - 1))
|> to_list)
[0; 1; 2; 3; 4; 5; 8]
let () =
OUnit.assert_equal
~cmp:(List.equal Int.equal)
(1 -- 10
|> map_while (fun x -> if x = 7 then `Stop else `Yield (x - 1))
|> to_list)
[0; 1; 2; 3; 4; 5]
let () = 1 -- 5 |> drop 2 |> to_list |> OUnit.assert_equal [ 3; 4; 5 ] let () = 1 -- 5 |> drop 2 |> to_list |> OUnit.assert_equal [ 3; 4; 5 ]
let () = 1 -- 5 |> rev |> to_list |> OUnit.assert_equal [ 5; 4; 3; 2; 1 ] let () = 1 -- 5 |> rev |> to_list |> OUnit.assert_equal [ 5; 4; 3; 2; 1 ]