use a new interface, unit -> 'a option, for Gen.

This commit is contained in:
Simon Cruanes 2014-01-30 01:41:51 +01:00
parent 660b75e0b4
commit 48ef226efd
4 changed files with 510 additions and 429 deletions

883
gen.ml

File diff suppressed because it is too large Load diff

44
gen.mli
View file

@ -27,8 +27,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Values of type ['a Gen.t] represent a possibly infinite sequence of values Values of type ['a Gen.t] represent a possibly infinite sequence of values
of type 'a. One can only iterate once on the sequence, as it is consumed of type 'a. One can only iterate once on the sequence, as it is consumed
by iteration/deconstruction/access. The exception {!EOG} (end of generator) by iteration/deconstruction/access. [None] is returned when the generator
is raised when the generator is empty. is exhausted.
The submodule {!Restart} provides utilities to work with The submodule {!Restart} provides utilities to work with
{b restartable generators}, that is, functions [unit -> 'a Gen.t] that {b restartable generators}, that is, functions [unit -> 'a Gen.t] that
@ -37,12 +37,9 @@ allow to build as many generators from the same source as needed.
(** {2 Global type declarations} *) (** {2 Global type declarations} *)
exception EOG type 'a t = unit -> 'a option
(** End of Generation *)
type 'a t = unit -> 'a
(** A generator may be called several times, yielding the next value (** A generator may be called several times, yielding the next value
each time. It raises EOG when it reaches the end. *) each time. It returns [None] when no elements remain *)
type 'a gen = 'a t type 'a gen = 'a t
@ -166,14 +163,20 @@ module type S = sig
(** Is the predicate true for at least one element? *) (** Is the predicate true for at least one element? *)
val for_all2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool val for_all2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool
(** Succeeds if all pairs of elements satisfy the predicate.
Ignores elements of an iterator if the other runs dry. *)
val exists2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool val exists2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool
(** Succeeds if some pair of elements satisfy the predicate.
Ignores elements of an iterator if the other runs dry. *)
val min : ?lt:('a -> 'a -> bool) -> 'a t -> 'a val min : ?lt:('a -> 'a -> bool) -> 'a t -> 'a
(** Minimum element, according to the given comparison function *) (** Minimum element, according to the given comparison function.
@raise Invalid_argument if the generator is empty *)
val max : ?lt:('a -> 'a -> bool) -> 'a t -> 'a val max : ?lt:('a -> 'a -> bool) -> 'a t -> 'a
(** Maximum element, see {!min} *) (** Maximum element, see {!min}
@raise Invalid_argument if the generator is empty *)
val eq : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t -> bool val eq : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t -> bool
(** Equality of generators. *) (** Equality of generators. *)
@ -188,8 +191,7 @@ module type S = sig
(** {2 Complex combinators} *) (** {2 Complex combinators} *)
val merge : 'a gen t -> 'a t val merge : 'a gen t -> 'a t
(** Pick elements fairly in each sub-generator. The given enum (** Pick elements fairly in each sub-generator. The merge of enums
must be finite (not its elements, though). The merge of enums
[e1, e2, ... en] picks one element in [e1], then one element in [e2], [e1, e2, ... en] picks one element in [e1], then one element in [e2],
then in [e3], ..., then in [en], and then starts again at [e1]. Once then in [e3], ..., then in [en], and then starts again at [e1]. Once
a generator is empty, it is skipped; when they are all empty, a generator is empty, it is skipped; when they are all empty,
@ -203,7 +205,7 @@ module type S = sig
val sorted_merge : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t -> 'a t val sorted_merge : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t -> 'a t
(** Merge two sorted sequences into a sorted sequence *) (** Merge two sorted sequences into a sorted sequence *)
val sorted_merge_n : ?cmp:('a -> 'a -> int) -> 'a gen t -> 'a t val sorted_merge_n : ?cmp:('a -> 'a -> int) -> 'a t list -> 'a t
(** Sorted merge of multiple sorted sequences *) (** Sorted merge of multiple sorted sequences *)
val tee : ?n:int -> 'a t -> 'a gen list val tee : ?n:int -> 'a t -> 'a gen list
@ -218,7 +220,8 @@ module type S = sig
val interleave : 'a t -> 'a t -> 'a t val interleave : 'a t -> 'a t -> 'a t
(** [interleave a b] yields an element of [a], then an element of [b], (** [interleave a b] yields an element of [a], then an element of [b],
and so on until the end of [a] or [b] is reached. *) and so on. When a generator is exhausted, this behaves like the
other generator. *)
val intersperse : 'a -> 'a t -> 'a t val intersperse : 'a -> 'a t -> 'a t
(** Put the separator element between all elements of the given enum *) (** Put the separator element between all elements of the given enum *)
@ -297,19 +300,18 @@ end
(** {2 Transient generators} *) (** {2 Transient generators} *)
val get : 'a t -> 'a val get : 'a t -> 'a option
(** Get the next value (** Get the next value *)
@raise EOG if there is no next value *)
val next : 'a t -> 'a val next : 'a t -> 'a option
(** Synonym for {!get} *) (** Synonym for {!get} *)
val get_safe : 'a t -> 'a option val get_exn : 'a t -> 'a
(** Get the next value, or return None *) (** Get the next value, or fails
@raise Invalid_argument if no element remains *)
val junk : 'a t -> unit val junk : 'a t -> unit
(** Drop the next value, discarding it. (** Drop the next value, discarding it. *)
@raise EOG if there is no next value *)
val repeatedly : (unit -> 'a) -> 'a t val repeatedly : (unit -> 'a) -> 'a t
(** Call the same function an infinite number of times (useful for instance (** Call the same function an infinite number of times (useful for instance

View file

@ -181,11 +181,11 @@ let gen l =
let x = ref (next l.data 0) in let x = ref (next l.data 0) in
fun () -> fun () ->
match !x with match !x with
| Nil -> raise Gen.EOG | Nil -> None
| Init _ -> assert false | Init _ -> assert false
| Node (k, v, a) -> | Node (k, v, a) ->
x := a.(0); x := a.(0);
k, !v Some (k, !v)
(** Add content of the iterator to the list *) (** Add content of the iterator to the list *)
let of_gen l gen = let of_gen l gen =

View file

@ -12,8 +12,8 @@ let pstrlist l = Utils.sprintf "%a"
let test_singleton () = let test_singleton () =
let gen = Gen.singleton 42 in let gen = Gen.singleton 42 in
OUnit.assert_equal 42 (Gen.get gen); OUnit.assert_equal (Some 42) (Gen.get gen);
OUnit.assert_raises Gen.EOG (fun () -> Gen.get gen); OUnit.assert_equal None (Gen.get gen);
let gen = Gen.singleton 42 in let gen = Gen.singleton 42 in
OUnit.assert_equal 1 (Gen.length gen); OUnit.assert_equal 1 (Gen.length gen);
() ()
@ -63,7 +63,7 @@ let test_persistent () =
let i = ref 0 in let i = ref 0 in
let gen () = let gen () =
let j = !i in let j = !i in
if j > 5 then raise Gen.EOG else (incr i; j) if j > 5 then None else (incr i; Some j)
in in
let e = Gen.persistent gen in let e = Gen.persistent gen in
OUnit.assert_equal [0;1;2;3;4;5] (GR.to_list e); OUnit.assert_equal [0;1;2;3;4;5] (GR.to_list e);
@ -86,7 +86,7 @@ let test_big_rr () =
() ()
let test_merge_sorted () = let test_merge_sorted () =
Gen.of_list [Gen.of_list [1;3;5]; Gen.of_list [0;1;1;3;4;6;10]; Gen.of_list [2;2;11]] [Gen.of_list [1;3;5]; Gen.of_list [0;1;1;3;4;6;10]; Gen.of_list [2;2;11]]
|> Gen.sorted_merge_n ?cmp:None |> Gen.sorted_merge_n ?cmp:None
|> Gen.to_list |> Gen.to_list
|> OUnit.assert_equal ~printer:Helpers.print_int_list [0;1;1;1;2;2;3;3;4;5;6;10;11] |> OUnit.assert_equal ~printer:Helpers.print_int_list [0;1;1;1;2;2;3;3;4;5;6;10;11]