(* Copyright (c) 2013, Simon Cruanes All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *) (** {1 Restartable generators} *) (** {2 Global type declarations} *) exception EOG (** End of Generation *) type 'a t = unit -> 'a (** A generator may be called several times, yielding the next value each time. It raises EOG when it reaches the end. *) type 'a gen = 'a t (** {2 Common signature for transient and restartable generators} *) module type S = sig type 'a t val empty : 'a t (** Empty generator, with no elements *) val singleton : 'a -> 'a t (** One-element generator *) val repeat : 'a -> 'a t (** Repeat same element endlessly *) val iterate : 'a -> ('a -> 'a) -> 'a t (** [iterate x f] is [[x; f x; f (f x); f (f (f x)); ...]] *) val unfold : ('b -> ('a * 'b) option) -> 'b -> 'a t (** Dual of {!fold}, with a deconstructing operation. It keeps on unfolding the ['b] value into a new ['b], and a ['a] which is yielded, until [None] is returned. *) (** {2 Basic combinators} *) val is_empty : _ t -> bool (** Check whether the enum is empty. *) val fold : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b (** Fold on the generator, tail-recursively *) val fold2 : ('c -> 'a -> 'b -> 'c) -> 'c -> 'a t -> 'b t -> 'c (** Fold on the two enums in parallel. Stops once one of the enums is exhausted. *) val reduce : ('a -> 'a -> 'a) -> 'a t -> 'a (** Fold on non-empty sequences (otherwise raise Invalid_argument) *) val scan : ('b -> 'a -> 'b) -> 'b -> 'a t -> 'b t (** Like {!fold}, but keeping successive values of the accumulator *) val iter : ('a -> unit) -> 'a t -> unit (** Iterate on the enum *) val iteri : (int -> 'a -> unit) -> 'a t -> unit (** Iterate on elements with their index in the enum, from 0 *) val iter2 : ('a -> 'b -> unit) -> 'a t -> 'b t -> unit (** Iterate on the two sequences. Stops once one of them is exhausted.*) val length : _ t -> int (** Length of an enum (linear time) *) val map : ('a -> 'b) -> 'a t -> 'b t (** Lazy map. No iteration is performed now, the function will be called when the result is traversed. *) val append : 'a t -> 'a t -> 'a t (** Append the two enums; the result contains the elements of the first, then the elements of the second enum. *) val flatten : 'a gen t -> 'a t (** Flatten the enumeration of generators *) val flatMap : ('a -> 'b gen) -> 'a t -> 'b t (** Monadic bind; each element is transformed to a sub-enum which is then iterated on, before the next element is processed, and so on. *) val mem : ?eq:('a -> 'a -> bool) -> 'a -> 'a t -> bool (** Is the given element, member of the enum? *) val take : int -> 'a t -> 'a t (** Take at most n elements *) val drop : int -> 'a t -> 'a t (** Drop n elements *) val nth : int -> 'a t -> 'a (** n-th element, or Not_found @raise Not_found if the generator contains less than [n] arguments *) val filter : ('a -> bool) -> 'a t -> 'a t (** Filter out elements that do not satisfy the predicate. *) val takeWhile : ('a -> bool) -> 'a t -> 'a t (** Take elements while they satisfy the predicate *) val dropWhile : ('a -> bool) -> 'a t -> 'a t (** Drop elements while they satisfy the predicate *) val filterMap : ('a -> 'b option) -> 'a t -> 'b t (** Maps some elements to 'b, drop the other ones *) val zipWith : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t (** Combine common part of the enums (stops when one is exhausted) *) val zip : 'a t -> 'b t -> ('a * 'b) t (** Zip together the common part of the enums *) val zipIndex : 'a t -> (int * 'a) t (** Zip elements with their index in the enum *) val unzip : ('a * 'b) t -> 'a t * 'b t (** Unzip into two sequences, splitting each pair *) val partition : ('a -> bool) -> 'a t -> 'a t * 'a t (** [partition p l] returns the elements that satisfy [p], and the elements that do not satisfy [p] *) val for_all : ('a -> bool) -> 'a t -> bool (** Is the predicate true for all elements? *) val exists : ('a -> bool) -> 'a t -> bool (** Is the predicate true for at least one element? *) val for_all2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool val exists2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool val min : ?lt:('a -> 'a -> bool) -> 'a t -> 'a (** Minimum element, according to the given comparison function *) val max : ?lt:('a -> 'a -> bool) -> 'a t -> 'a (** Maximum element, see {!min} *) val eq : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t -> bool (** Equality of generators. *) val lexico : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t -> int (** Lexicographic comparison of generators. If the common prefix is the same, the shortest one is considered as smaller than the other. *) val compare : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t -> int (** Synonym for {! lexico} *) (** {2 Complex combinators} *) val merge : 'a gen t -> 'a t (** Pick elements fairly in each sub-generator. The given enum must be finite (not its elements, though). The merge of enums [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 a generator is empty, it is skipped; when they are all empty, their merge is also empty. For instance, [merge [1;3;5] [2;4;6]] will be [1;2;3;4;5;6]. *) val intersection : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t -> 'a t (** Intersection of two sorted sequences. Only elements that occur in both inputs appear in the output *) val sorted_merge : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t -> 'a t (** Merge two sorted sequences into a sorted sequence *) val sorted_merge_n : ?cmp:('a -> 'a -> int) -> 'a gen t -> 'a t (** Sorted merge of multiple sorted sequences *) val tee : ?n:int -> 'a t -> 'a gen list (** Duplicate the enum into [n] generators (default 2). The generators share the same underlying instance of the enum, so the optimal case is when they are consumed evenly *) val round_robin : ?n:int -> 'a t -> 'a gen list (** Split the enum into [n] generators in a fair way. Elements with [index = k mod n] with go to the k-th enum. [n] default value is 2. *) val interleave : 'a t -> 'a t -> 'a t (** [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. *) val intersperse : 'a -> 'a t -> 'a t (** Put the separator element between all elements of the given enum *) val product : 'a t -> 'b t -> ('a * 'b) t (** Cartesian product, in no predictable order. Works even if some of the arguments are infinite. *) val group : ?eq:('a -> 'a -> bool) -> 'a t -> 'a list t (** Group equal consecutive elements together. *) val uniq : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t (** Remove consecutive duplicate elements. Basically this is like [fun e -> map List.hd (group e)]. *) val sort : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t (** Sort according to the given comparison function. The enum must be finite. *) val sort_uniq : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t (** Sort and remove duplicates. The enum must be finite. *) (* TODO later val permutations : 'a t -> 'a gen t (** Permutations of the enum. Each permutation becomes unavailable once the next one is produced. *) val combinations : int -> 'a t -> 'a t t (** Combinations of given length. *) val powerSet : 'a t -> 'a t t (** All subsets of the enum (in no particular order) *) *) (** {2 Basic conversion functions} *) val of_list : 'a list -> 'a t (** Enumerate elements of the list *) val to_list : 'a t -> 'a list (** non tail-call trasnformation to list, in the same order *) val to_rev_list : 'a t -> 'a list (** Tail call conversion to list, in reverse order (more efficient) *) val to_array : 'a t -> 'a array (** Convert the enum to an array (not very efficient) *) val of_array : ?start:int -> ?len:int -> 'a array -> 'a t (** Iterate on (a slice of) the given array *) val rand_int : int -> int t (** Random ints in the given range. *) val int_range : int -> int -> int t (** [int_range a b] enumerates integers between [a] and [b], included. [a] is assumed to be smaller than [b]. *) module Infix : sig val (--) : int -> int -> int t (** Synonym for {! int_range} *) val (>>=) : 'a t -> ('a -> 'b gen) -> 'b t (** Monadic bind operator *) end val (--) : int -> int -> int t (** Synonym for {! int_range} *) val (>>=) : 'a t -> ('a -> 'b gen) -> 'b t (** Monadic bind operator *) val pp : ?start:string -> ?stop:string -> ?sep:string -> ?horizontal:bool -> (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit (** Pretty print the content of the generator on a formatter. *) end (** {2 Transient generators} *) let empty () = raise EOG let singleton x = let first = ref true in fun () -> if !first then (first := false; x) else raise EOG let rec repeat x () = x let repeatedly f () = f () let iterate x f = let cur = ref x in fun () -> let x = !cur in cur := f !cur; x let next gen = gen () let get gen = gen () let get_safe gen = try Some (gen ()) with EOG -> None let junk gen = ignore (gen ()) let rec fold f acc gen = let acc, stop = try f acc (gen ()), false with EOG -> acc, true in if stop then acc else fold f acc gen let rec fold2 f acc e1 e2 = let acc, stop = try f acc (e1()) (e2()), false with EOG -> acc, true in if stop then acc else fold2 f acc e1 e2 let reduce f g = let acc = try g () with EOG -> raise (Invalid_argument "reduce") in fold f acc g (* Dual of {!fold}, with a deconstructing operation *) let unfold f acc = let acc = ref acc in fun () -> match f !acc with | None -> raise EOG | Some (x, acc') -> acc := acc'; x let iter f gen = try while true do f (gen ()) done with EOG -> () let iteri f gen = let n = ref 0 in try while true do f !n (gen ()); incr n done with EOG -> () let is_empty enum = try ignore (enum ()); false with EOG -> true let length gen = fold (fun acc _ -> acc + 1) 0 gen let scan f acc g = let acc = ref acc in let first = ref true in fun () -> if !first then (first := false; !acc) else begin acc := f !acc (g ()); !acc end let iter2 f gen1 gen2 = try while true do f (gen1 ()) (gen2 ()) done; with EOG -> () (** {3 Lazy} *) let map f gen () = f (gen ()) let append gen1 gen2 = let gen = ref gen1 in let first = ref true in (* get next element *) let rec next () = try !gen () with EOG -> if !first then begin first := false; gen := gen2; (* switch to the second generator *) next () end else raise EOG (* done *) in next let flatten next_gen = let gen = ref empty in (* get next element *) let rec next () = try !gen () with EOG -> (* jump to next sub-enum *) gen := next_gen (); next () in next let flatMap f next_elem = let gen = ref empty in (* get next element *) let rec next () = try !gen () with EOG -> (* enumerate f (next element) *) let x = next_elem () in gen := f x; next () (* try again, with [gen = f x] *) in next let mem ?(eq=(=)) x gen = try iter (fun y -> if eq x y then raise Exit) gen; false with Exit -> true let take n gen = assert (n >= 0); let count = ref 0 in (* how many yielded elements *) fun () -> if !count = n then raise EOG else begin incr count; gen () end let drop n gen = assert (n >= 0); let dropped = ref false in fun () -> if !dropped then gen() else begin (* drop [n] elements and yield the next element *) dropped := true; for i = 0 to n-1 do ignore (gen()) done; gen() end let nth n gen = assert (n>=0); let rec iter i = let x = gen () in if n = i then x else iter (i+1) in try iter 0 with EOG -> raise Not_found let filter p gen = let rec next () = (* wrap exception into option, for next to be tailrec *) match (try Some (gen ()) with EOG -> None) with | None -> raise EOG | Some x -> if p x then x (* yield element *) else next () (* discard element *) in next let takeWhile p gen = let rec next () = let x = gen () in if p x then x else raise EOG in next let dropWhile p gen = let stop_drop = ref false in let rec next () = let x = gen () in if !stop_drop then x (* yield *) else if p x then next () (* continue dropping *) else (stop_drop := true; x) (* stop dropping *) in next let filterMap f gen = (* tailrec *) let rec next () = let x = gen () in match f x with | None -> next () | Some y -> y in next let zipWith f a b = fun () -> f (a()) (b()) let zip a b = fun () -> a(), b() let zipIndex gen = let r = ref 0 in fun () -> let x = gen () in let n = !r in incr r; n, x let unzip gen = let stop = ref false in let q1 = Queue.create () in let q2 = Queue.create () in let next_left () = if Queue.is_empty q1 then if !stop then raise EOG else try let x, y = gen() in Queue.push y q2; x with EOG -> stop := true; raise EOG else Queue.pop q1 in let next_right () = if Queue.is_empty q2 then if !stop then raise EOG else try let x, y = gen() in Queue.push x q1; y with EOG -> stop := true; raise EOG else Queue.pop q2 in next_left, next_right (* [partition p l] returns the elements that satisfy [p], and the elements that do not satisfy [p] *) let partition p gen = let qtrue = Queue.create () in let qfalse = Queue.create () in let stop = ref false in let rec nexttrue () = if Queue.is_empty qtrue then if !stop then raise EOG else try let x = gen() in if p x then x else (Queue.push x qfalse; nexttrue()) with EOG -> stop:=true; raise EOG else Queue.pop qtrue and nextfalse() = if Queue.is_empty qfalse then if !stop then raise EOG else try let x = gen() in if p x then (Queue.push x qtrue; nextfalse()) else x with EOG -> stop:= true; raise EOG else Queue.pop qfalse in nexttrue, nextfalse exception GenExit let for_all p gen = try iter (fun x -> if not (p x) then raise GenExit) gen; true with GenExit -> false let exists p gen = try iter (fun x -> if p x then raise GenExit) gen; false with GenExit -> true let for_all2 p e1 e2 = try iter2 (fun x y -> if not (p x y) then raise Exit) e1 e2; true with Exit -> false let exists2 p e1 e2 = try iter2 (fun x y -> if p x y then raise Exit) e1 e2; false with Exit -> true let min ?(lt=fun x y -> x < y) gen = let first = try gen () with EOG -> raise Not_found in fold (fun min x -> if lt x min then x else min) first gen let max ?(lt=fun x y -> x < y) gen = let first = try gen () with EOG -> raise Not_found in fold (fun max x -> if lt max x then x else max) first gen let eq ?(eq=(=)) gen1 gen2 = let rec check () = let x1 = try Some (gen1 ()) with EOG -> None in let x2 = try Some (gen2 ()) with EOG -> None in match x1, x2 with | None, None -> true | Some x1, Some x2 when eq x1 x2 -> check () | _ -> false in check () let lexico ?(cmp=Pervasives.compare) gen1 gen2 = let rec lexico () = let x1 = try Some (gen1 ()) with EOG -> None in let x2 = try Some (gen2 ()) with EOG -> None in match x1, x2 with | None, None -> 0 | Some x1, Some x2 -> let c = cmp x1 x2 in if c <> 0 then c else lexico () | Some _, None -> 1 | None, Some _ -> -1 in lexico () let compare ?cmp gen1 gen2 = lexico ?cmp gen1 gen2 (** {3 Complex combinators} *) let merge gen = (* list of sub-enums *) let l = fold (fun acc x -> x::acc) [] gen in let l = List.rev l in let q = Queue.create () in List.iter (fun gen' -> Queue.push gen' q) l; (* recursive function to get next element *) let rec next () = if Queue.is_empty q then raise EOG else let gen = Queue.pop q in match (try Some (gen ()) with EOG -> None) with | None -> next () (* exhausted generator, drop it *) | Some x -> Queue.push gen q; (* put generator at the end, return x *) x in next let intersection ?(cmp=Pervasives.compare) gen1 gen2 = let next1 () = try Some (gen1 ()) with EOG -> None in let next2 () = try Some (gen2 ()) with EOG -> None in let x1 = ref (next1 ()) in let x2 = ref (next2 ()) in let rec next () = match !x1, !x2 with | None, None -> raise EOG | Some y1, Some y2 -> let c = cmp y1 y2 in if c = 0 (* equal elements, yield! *) then (x1 := next1 (); x2 := next2 (); y1) else if c < 0 (* drop y1 *) then (x1 := next1 (); next ()) else (* drop y2 *) (x2 := next2 (); next ()) | Some _, None | None, Some _ -> raise EOG in next let sorted_merge ?(cmp=Pervasives.compare) gen1 gen2 = let next1 () = try Some (gen1 ()) with EOG -> None in let next2 () = try Some (gen2 ()) with EOG -> None in let x1 = ref (next1 ()) in let x2 = ref (next2 ()) in fun () -> match !x1, !x2 with | None, None -> raise EOG | Some y1, Some y2 -> if cmp y1 y2 <= 0 then (x1 := next1 (); y1) else (x2 := next2 (); y2) | Some y1, None -> x1 := next1 (); y1 | None, Some y2 -> x2 := next2 (); y2 (** {4 Mutable heap (taken from heap.ml to avoid dependencies)} *) module Heap = struct type 'a t = { mutable tree : 'a tree; cmp : 'a -> 'a -> int; } (** A pairing tree heap with the given comparison function *) and 'a tree = | Empty | Node of 'a * 'a tree * 'a tree let empty ~cmp = { tree = Empty; cmp; } let is_empty h = match h.tree with | Empty -> true | Node _ -> false let rec union ~cmp t1 t2 = match t1, t2 with | Empty, _ -> t2 | _, Empty -> t1 | Node (x1, l1, r1), Node (x2, l2, r2) -> if cmp x1 x2 <= 0 then Node (x1, union ~cmp t2 r1, l1) else Node (x2, union ~cmp t1 r2, l2) let insert h x = h.tree <- union ~cmp:h.cmp (Node (x, Empty, Empty)) h.tree let pop h = match h.tree with | Empty -> raise Not_found | Node (x, l, r) -> h.tree <- union ~cmp:h.cmp l r; x end let sorted_merge_n ?(cmp=Pervasives.compare) gen = (* make a heap of (value, generator) *) let cmp (v1,_) (v2,_) = cmp v1 v2 in let heap = Heap.empty ~cmp in (* add initial values *) iter (fun gen' -> try let x = gen' () in Heap.insert heap (x, gen') with EOG -> ()) gen; fun () -> if Heap.is_empty heap then raise EOG else begin let x, gen = Heap.pop heap in try let y = gen () in Heap.insert heap (y, gen); (* insert next value *) x with EOG -> x (* gen is empty *) end let round_robin ?(n=2) gen = (* array of queues, together with their index *) let qs = Array.init n (fun i -> Queue.create ()) in let cur = ref 0 in (* get next element for the i-th queue *) let rec next i = let q = qs.(i) in if Queue.is_empty q then update_to_i i (* consume generator *) else Queue.pop q (* consume [gen] until some element for [i]-th generator is available. It raises EOG if [gen] is exhausted before *) and update_to_i i = let x = gen () in let j = !cur in cur := (j+1) mod n; (* move cursor to next generator *) let q = qs.(j) in if j = i then begin assert (Queue.is_empty q); x (* return the element *) end else begin Queue.push x q; update_to_i i (* continue consuming [gen] *) end in (* generators *) let l = Array.mapi (fun i _ -> (fun () -> next i)) qs in Array.to_list l (* Duplicate the enum into [n] generators (default 2). The generators share the same underlying instance of the enum, so the optimal case is when they are consumed evenly *) let tee ?(n=2) gen = (* array of queues, together with their index *) let qs = Array.init n (fun i -> Queue.create ()) in let finished = ref false in (* is [gen] exhausted? *) (* get next element for the i-th queue *) let rec next i = if Queue.is_empty qs.(i) then if !finished then raise EOG else get_next i (* consume generator *) else Queue.pop qs.(i) (* consume one more element *) and get_next i = try let x = gen () in for j = 0 to n-1 do if j <> i then Queue.push x qs.(j) done; x with EOG -> finished := true; raise EOG in (* generators *) let l = Array.mapi (fun i _ -> (fun () -> next i)) qs in Array.to_list l let round_robin ?(n=2) gen = (* array of queues, together with their index *) let qs = Array.init n (fun i -> Queue.create ()) in let cur = ref 0 in let stop = ref false in (* get next element for the i-th queue *) let rec next i = let q = qs.(i) in if Queue.is_empty q then update_to_i i (* consume generator *) else Queue.pop q (* consume [gen] until some element for [i]-th generator is available. It raises EOG if [gen] is exhausted before *) and update_to_i i = (if !stop then raise EOG); let x = try gen () with EOG -> stop := true; raise EOG in let j = !cur in cur := (j+1) mod n; (* move cursor to next generator *) let q = qs.(j) in if j = i then begin assert (Queue.is_empty q); x (* return the element *) end else begin Queue.push x q; update_to_i i (* continue consuming [gen] *) end in (* generators *) let l = Array.mapi (fun i _ -> fun () -> next i) qs in Array.to_list l (* Yield elements from a and b alternatively *) let interleave gen_a gen_b = let left = ref true in (* left or right? *) fun () -> if !left then (left := false; gen_a ()) else (left := true; gen_b ()) (* Put [x] between elements of [enum] *) let intersperse x gen = let next_elem = ref None in (* must see whether the gen is empty (first element must be from enum) *) try next_elem := Some (gen ()); (* get next element *) let rec next () = match !next_elem with | None -> next_elem := Some (gen ()); x (* yield x, gen is not exhausted *) | Some y -> next_elem := None; y (* yield element of gen *) in next with EOG -> fun () -> raise EOG (* Cartesian product *) let product gena genb = let all_a = ref [] in let all_b = ref [] in let cur = ref `GetLeft in let rec next () = match !cur with | `Stop -> raise EOG | `GetLeft -> let xa = try Some (gena()) with EOG -> None in begin match xa with | None -> cur := `GetRight | Some a -> all_a := a :: !all_a; cur := `ProdLeft (a, !all_b) end; next () | `GetRight -> let xb = try Some (genb()) with EOG -> None in begin match xb with | None -> cur := `Stop; raise EOG | Some b -> all_b := b::!all_b; cur := `ProdRight (b, !all_a) end; next () | `ProdLeft (_, []) -> cur := `GetRight; next() | `ProdLeft (x, y::l) -> cur := `ProdLeft (x, l); x, y | `ProdRight (_, []) -> cur := `GetLeft; next() | `ProdRight (y, x::l) -> cur := `ProdRight (y, l); x, y in next (* Group equal consecutive elements together. *) let group ?(eq=(=)) gen = try let cur = ref [gen ()] in let rec next () = (* try to get an element *) let next_x = if !cur = [] then None else try Some (gen ()) with EOG -> None in match next_x, !cur with | None, [] -> raise EOG | None, l -> cur := []; l | Some x, y::_ when eq x y -> cur := x::!cur; next () (* same group *) | Some x, l -> cur := [x]; l in next with EOG -> fun () -> raise EOG let uniq ?(eq=(=)) gen = let prev = ref (Obj.magic 0) in let first = ref true in let rec next () = let x = gen () in if !first then (first := false; prev := x; x) else if eq x !prev then next () else (prev := x; x) in next let sort ?(cmp=Pervasives.compare) gen = (* build heap *) let h = Heap.empty ~cmp in iter (Heap.insert h) gen; fun () -> if Heap.is_empty h then raise EOG else Heap.pop h (* FIXME: use a set *) let sort_uniq ?(cmp=Pervasives.compare) gen = uniq ~eq:(fun x y -> cmp x y = 0) (sort ~cmp gen) (* let permutations enum = failwith "not implemented" (* TODO *) let combinations n enum = assert (n >= 0); failwith "not implemented" (* TODO *) let powerSet enum = failwith "not implemented" *) (** {3 Conversion} *) let of_list l = let l = ref l in fun () -> match !l with | [] -> raise EOG | x::l' -> l := l'; x let to_rev_list gen = fold (fun acc x -> x :: acc) [] gen let to_list gen = List.rev (to_rev_list gen) let to_array gen = let l = to_rev_list gen in let a = Array.of_list l in let n = Array.length a in for i = 0 to (n-1) / 2 do let tmp = a.(i) in a.(i) <- a.(n-i-1); a.(n-i-1) <- tmp done; a let of_array ?(start=0) ?len a = let len = match len with | None -> Array.length a - start | Some n -> assert (n + start < Array.length a); n in let i = ref start in fun () -> if !i >= start + len then raise EOG else (let x = a.(!i) in incr i; x) let rand_int i = repeatedly (fun () -> Random.int i) let int_range i j = let r = ref i in fun () -> let x = !r in if x > j then raise EOG else begin incr r; x end let pp ?(start="") ?(stop="") ?(sep=",") ?(horizontal=false) pp_elem formatter gen = (if horizontal then Format.pp_open_hbox formatter () else Format.pp_open_hvbox formatter 0); Format.pp_print_string formatter start; let rec next is_first = let continue_ = try let x = gen () in (if not is_first then begin Format.pp_print_string formatter sep; Format.pp_print_space formatter (); pp_elem formatter x end else pp_elem formatter x); true with EOG -> false in if continue_ then next false in next true; Format.pp_print_string formatter stop; Format.pp_close_box formatter () module Infix = struct let (--) = int_range let (>>=) x f = flatMap f x end include Infix module Restart = struct type 'a t = unit -> 'a gen type 'a restartable = 'a t let lift f e = f (e ()) let lift2 f e1 e2 = f (e1 ()) (e2 ()) let empty () = empty let singleton x () = singleton x let iterate x f () = iterate x f let repeat x () = repeat x let repeatedly f () = repeatedly f let unfold f acc () = unfold f acc let cycle enum = assert (not (is_empty enum)); fun () -> let gen = ref (enum ()) in let rec next () = try !gen () with EOG -> gen := enum (); next () in next let is_empty e = is_empty (e ()) let fold f acc e = fold f acc (e ()) let fold2 f acc e1 e2 = fold2 f acc (e1 ()) (e2 ()) let reduce f e = reduce f (e ()) let scan f acc e () = scan f acc (e ()) let iter f e = iter f (e ()) let iteri f e = iteri f (e ()) let iter2 f e1 e2 = iter2 f (e1 ()) (e2 ()) let length e = length (e ()) let map f e () = map f (e ()) let append e1 e2 () = append (e1 ()) (e2 ()) let flatten e () = flatten (e ()) let flatMap f e () = flatMap f (e ()) let mem ?eq x e = mem ?eq x (e ()) let take n e () = take n (e ()) let drop n e () = drop n (e ()) let nth n e = nth n (e ()) let filter p e () = filter p (e ()) let takeWhile p e () = takeWhile p (e ()) let dropWhile p e () = dropWhile p (e ()) let filterMap f e () = filterMap f (e ()) let zipWith f e1 e2 () = zipWith f (e1 ()) (e2 ()) let zip e1 e2 () = zip (e1 ()) (e2 ()) let zipIndex e () = zipIndex (e ()) let unzip e = map fst e, map snd e let partition p e = filter p e, filter (fun x -> not (p x)) e let for_all p e = for_all p (e ()) let exists p e = exists p (e ()) let for_all2 p e1 e2 = for_all2 p (e1 ()) (e2 ()) let exists2 p e1 e2 = exists2 p (e1 ()) (e2 ()) let min ?lt e = min ?lt (e ()) let max ?lt e = max ?lt (e ()) let ___eq = eq let eq ?eq e1 e2 = ___eq ?eq (e1 ()) (e2 ()) let lexico ?cmp e1 e2 = lexico ?cmp (e1 ()) (e2 ()) let compare ?cmp e1 e2 = compare ?cmp (e1 ()) (e2 ()) let merge e () = merge (e ()) let intersection ?cmp e1 e2 () = intersection ?cmp (e1 ()) (e2 ()) let sorted_merge ?cmp e1 e2 () = sorted_merge ?cmp (e1 ()) (e2 ()) let sorted_merge_n ?cmp e () = sorted_merge_n ?cmp (e ()) let tee ?n e = tee ?n (e ()) let round_robin ?n e = round_robin ?n (e ()) let interleave e1 e2 () = interleave (e1 ()) (e2 ()) let intersperse x e () = intersperse x (e ()) let product e1 e2 () = product (e1 ()) (e2 ()) let group ?eq e () = group ?eq (e ()) let uniq ?eq e () = uniq ?eq (e ()) let sort ?(cmp=Pervasives.compare) enum = fun () -> (* build heap *) let h = Heap.empty ~cmp in iter (Heap.insert h) enum; fun () -> if Heap.is_empty h then raise EOG else Heap.pop h let sort_uniq ?(cmp=Pervasives.compare) e = let e' = sort ~cmp e in uniq ~eq:(fun x y -> cmp x y = 0) e' let of_list l () = of_list l let to_rev_list e = to_rev_list (e ()) let to_list e = to_list (e ()) let to_array e = to_array (e ()) let of_array ?start ?len a () = of_array ?start ?len a let rand_int i () = rand_int i let int_range i j () = int_range i j module Infix = struct let (--) = int_range let (>>=) x f = flatMap f x end include Infix let pp ?start ?stop ?sep ?horizontal pp_elem fmt e = pp ?start ?stop ?sep ?horizontal pp_elem fmt (e ()) end (** {2 Generator functions} *) let start g = g () (** {4 Mutable double-linked list, similar to {! Deque.t} *) module MList = struct type 'a t = 'a node option ref and 'a node = { content : 'a; mutable prev : 'a node; mutable next : 'a node; } let create () = ref None let is_empty d = match !d with | None -> true | Some _ -> false let push_back d x = match !d with | None -> let rec elt = { content = x; prev = elt; next = elt; } in d := Some elt | Some first -> let elt = { content = x; next=first; prev=first.prev; } in first.prev.next <- elt; first.prev <- elt (* conversion to enum *) let to_enum d = fun () -> match !d with | None -> (fun () -> raise EOG) | Some first -> let cur = ref first in (* current elemnt of the list *) let stop = ref false in (* are we done yet? *) (fun () -> (if !stop then raise EOG); let x = (!cur).content in cur := (!cur).next; (if !cur == first then stop := true); (* EOG, we made a full cycle *) x) end (** Store content of the generator in an enum *) let persistent gen = let l = MList.create () in (try while true do MList.push_back l (gen ()); done with EOG -> ()); (* done recursing through the generator *) MList.to_enum l