From 173da383665e3cb8015e40e40c059d141fc9829a Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sat, 19 Mar 2022 10:24:04 -0400 Subject: [PATCH] use Seq, remove Stream entirely to be ready for OCaml 5.0; add of_gen_once --- iter.opam | 1 + src/Iter.ml | 80 +++++++++++++++++++--------------------------- src/Iter.mli | 25 ++++++++------- src/IterLabels.mli | 18 ++++------- src/dune | 2 +- 5 files changed, 55 insertions(+), 71 deletions(-) diff --git a/iter.opam b/iter.opam index 1ea7246..af35350 100644 --- a/iter.opam +++ b/iter.opam @@ -13,6 +13,7 @@ build: [ depends: [ "base-bytes" "result" + "seq" "ocaml" { >= "4.03.0" } "dune" { >= "1.1" } "dune-configurator" diff --git a/src/Iter.ml b/src/Iter.ml index 613f5f9..aae6d2d 100644 --- a/src/Iter.ml +++ b/src/Iter.ml @@ -344,14 +344,11 @@ module MList = struct let to_gen l = _to_next () l - let to_stream l = - Stream.from (_to_next 42 l) (* 42=magic cookiiiiiie *) - - let to_klist l = + let to_seq l = let rec make (l,i) () = match l with - | Nil -> `Nil + | Nil -> Seq.Nil | Cons (_, n, tl) when i = !n -> make (!tl,0) () - | Cons (a, _, _) -> `Cons (a.(i), make (l,i+1)) + | Cons (a, _, _) -> Seq.Cons (a.(i), make (l,i+1)) in make (l,0) end @@ -361,31 +358,22 @@ let persistent seq = (*$R let printer = pp_ilist in - let stream = Stream.from (fun i -> if i < 5 then Some i else None) in - let seq = of_stream stream in - OUnit.assert_equal ~printer [0;1;2;3;4] (seq |> to_list); - OUnit.assert_equal ~printer [] (seq |> to_list); + let iter = of_gen_once (let i=ref (-1) in fun() -> incr i; if !i < 5 then Some !i else None) in + (* consume iter into a persistent version of itself *) + let iter' = persistent iter in + OUnit.assert_raises OneShotSequence (fun () -> iter |> to_list); + OUnit.assert_equal ~printer [0;1;2;3;4] (iter' |> to_list); + OUnit.assert_equal ~printer [0;1;2;3;4] (iter' |> to_list); + OUnit.assert_equal ~printer [0;1;2;3;4] (iter' |> to_seq_persistent |> of_seq |> to_list); *) (*$R let printer = pp_ilist in - let stream = Stream.from (fun i -> if i < 5 then Some i else None) in - let seq = of_stream stream in - (* consume seq into a persistent version of itself *) - let seq' = persistent seq in - OUnit.assert_equal ~printer [] (seq |> to_list); - OUnit.assert_equal ~printer [0;1;2;3;4] (seq' |> to_list); - OUnit.assert_equal ~printer [0;1;2;3;4] (seq' |> to_list); - OUnit.assert_equal ~printer [0;1;2;3;4] (seq' |> to_stream |> of_stream |> to_list); -*) - -(*$R - let printer = pp_ilist in - let seq = (0 -- 10_000) in - let seq' = persistent seq in - OUnit.assert_equal 10_001 (length seq'); - OUnit.assert_equal 10_001 (length seq'); - OUnit.assert_equal ~printer [0;1;2;3] (seq' |> take 4 |> to_list); + let iter = (0 -- 10_000) in + let iter' = persistent iter in + OUnit.assert_equal 10_001 (length iter'); + OUnit.assert_equal 10_001 (length iter'); + OUnit.assert_equal ~printer [0;1;2;3] (iter' |> take 4 |> to_list); *) type 'a lazy_state = @@ -542,8 +530,7 @@ let[@inline] product outer inner k = outer (fun x -> inner (fun y -> k (x,y))) (*$R - let stream = Stream.from (fun i -> if i < 3 then Some i else None) in - let a = of_stream stream in + let a = 0 -- 2 in let b = of_list ["a";"b";"c"] in let s = product a b |> map (fun (x,y) -> y,x) |> to_list |> List.sort compare in @@ -1041,11 +1028,13 @@ let array_slice a i j k = k a.(idx); (* iterate on sub-array *) done -let of_stream s k = Stream.iter k s +let rec of_seq l k = match l() with + | Seq.Nil -> () + | Seq.Cons (x,tl) -> k x; of_seq tl k -let to_stream seq = +let to_seq_persistent seq = let l = MList.of_iter seq in - MList.to_stream l + MList.to_seq l let[@inline] to_stack s seq = iter (fun x -> Stack.push x s) seq @@ -1169,29 +1158,26 @@ let to_set (type s) (type v) m seq = S.empty seq type 'a gen = unit -> 'a option -type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist] + +(* consume the generator to build a MList *) +let rec of_gen1_ g k = match g () with + | None -> () + | Some x -> k x; of_gen1_ g k + +let of_gen_once g = + let first = ref true in + fun k -> + if !first then first := false else raise OneShotSequence; + of_gen1_ g k let of_gen g = - (* consume the generator to build a MList *) - let rec iter1 k = match g () with - | None -> () - | Some x -> k x; iter1 k - in - let l = MList.of_iter iter1 in + let l = MList.of_iter (of_gen1_ g) in MList.to_iter l let to_gen seq = let l = MList.of_iter seq in MList.to_gen l -let rec of_klist l k = match l() with - | `Nil -> () - | `Cons (x,tl) -> k x; of_klist tl k - -let to_klist seq = - let l = MList.of_iter seq in - MList.to_klist l - (** {2 Functorial conversions between sets and iterators} *) module Set = struct diff --git a/src/Iter.mli b/src/Iter.mli index 35d8db9..8cc4f92 100644 --- a/src/Iter.mli +++ b/src/Iter.mli @@ -25,7 +25,7 @@ (i.e. calling it several times always iterates on the same set of elements, for instance List.iter or Map.iter), then the resulting {!t} object is also repeatable. For {b one-time iter functions} - such as iteration on a file descriptor or a {!Stream}, + such as iteration on a file descriptor or a {!Seq}, the {!persistent} function can be used to iterate and store elements in a memory structure; the result is an iterator that iterates on the elements of this memory structure, cheaply and repeatably. @@ -567,11 +567,14 @@ val of_opt : 'a option -> 'a t (** Iterate on 0 or 1 values. @since 0.5.1 *) -val of_stream : 'a Stream.t -> 'a t -(** Iterator of elements of a stream (usable only once) *) +val of_seq : 'a Seq.t -> 'a t +(** Iterator of elements of a {!Seq.t}. + @since NEXT_RELEASE *) -val to_stream : 'a t -> 'a Stream.t -(** Convert to a stream. linear in memory and time (a copy is made in memory) *) +val to_seq_persistent : 'a t -> 'a Seq.t +(** Convert to a {!Seq}. Linear in memory and time (a copy is made in memory). + This does not work on infinite iterators. + @since NEXT_RELEASE *) val to_stack : 'a Stack.t -> 'a t -> unit (** Push elements of the iterator on the stack *) @@ -648,20 +651,18 @@ val to_set : (module Set.S with type elt = 'a and type t = 'b) -> 'a t -> 'b (** Convert the iterator to a set, given the proper set module *) type 'a gen = unit -> 'a option -type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist] val of_gen : 'a gen -> 'a t (** Traverse eagerly the generator and build an iterator from it *) +val of_gen_once : 'a gen -> 'a t +(** One shot iterator using this generator. + It must not be traversed twice. + @since NEXT_RELEASE *) + val to_gen : 'a t -> 'a gen (** Make the iterator persistent (O(n)) and then iterate on it. Eager. *) -val of_klist : 'a klist -> 'a t -(** Iterate on the lazy list *) - -val to_klist : 'a t -> 'a klist -(** Make the iterator persistent and then iterate on it. Eager. *) - (** {2 Sets} *) module Set : sig diff --git a/src/IterLabels.mli b/src/IterLabels.mli index 8c79188..676937e 100644 --- a/src/IterLabels.mli +++ b/src/IterLabels.mli @@ -531,11 +531,14 @@ val of_opt : 'a option -> 'a t (** Iterate on 0 or 1 values. @since 0.5.1 *) -val of_stream : 'a Stream.t -> 'a t -(** Iterator of elements of a stream (usable only once) *) +val of_seq : 'a Seq.t -> 'a t +(** Iterator of elements of a {!Seq.t}. + @since NEXT_RELEASE *) -val to_stream : 'a t -> 'a Stream.t -(** Convert to a stream. linear in memory and time (a copy is made in memory) *) +val to_seq_persistent : 'a t -> 'a Seq.t +(** Convert to a {!Seq}. Linear in memory and time (a copy is made in memory). + This does not work on infinite iterators. + @since NEXT_RELEASE *) val to_stack : 'a Stack.t -> 'a t -> unit (** Push elements of the iterator on the stack *) @@ -613,7 +616,6 @@ val to_set : (module Set.S with type elt = 'a and type t = 'b) -> 'a t -> 'b (** Convert the iterator to a set, given the proper set module *) type 'a gen = unit -> 'a option -type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist] val of_gen : 'a gen -> 'a t (** Traverse eagerly the generator and build an iterator from it *) @@ -621,12 +623,6 @@ val of_gen : 'a gen -> 'a t val to_gen : 'a t -> 'a gen (** Make the iterator persistent (O(n)) and then iterate on it. Eager. *) -val of_klist : 'a klist -> 'a t -(** Iterate on the lazy list *) - -val to_klist : 'a t -> 'a klist -(** Make the iterator persistent and then iterate on it. Eager. *) - (** {3 Sets} *) module Set : sig diff --git a/src/dune b/src/dune index 391ca8b..af66c97 100644 --- a/src/dune +++ b/src/dune @@ -15,7 +15,7 @@ (wrapped false) (modules Iter IterLabels Iter_shims_) (flags :standard -nolabels) - (libraries bytes result)) + (libraries bytes result seq)) (env