From d638038089a5d15c4c67846680ce2ba447acbd08 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 8 Aug 2014 20:26:04 +0200 Subject: [PATCH] CCSequence now shares code with the 'sequence' library; merged the .mli so it reflects versions properly --- core/CCSequence.ml | 692 +------------------------------------------- core/CCSequence.mli | 238 +++++++++++++-- 2 files changed, 215 insertions(+), 715 deletions(-) mode change 100644 => 120000 core/CCSequence.ml diff --git a/core/CCSequence.ml b/core/CCSequence.ml deleted file mode 100644 index b2e15ded..00000000 --- a/core/CCSequence.ml +++ /dev/null @@ -1,691 +0,0 @@ -(* -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 Transient iterators, that abstract on a finite sequence of elements.} *) - -(** Sequence abstract iterator type *) -type 'a t = ('a -> unit) -> unit - -type 'a sequence = 'a t - -type (+'a, +'b) t2 = ('a -> 'b -> unit) -> unit - (** Sequence of pairs of values of type ['a] and ['b]. *) - -(** Build a sequence from a iter function *) -let from_iter f = f - -(** Call the function repeatedly until it returns None. This - sequence is transient, use {!persistent} if needed! *) -let from_fun f = - fun k -> - let rec next () = - match f () with - | None -> () - | Some x -> (k x; next ()) - in next () - -let empty = fun k -> () - -let singleton x = fun k -> k x - -(** Infinite sequence of the same element *) -let repeat x = fun k -> while true do k x done - -(** [iterate f x] is the infinite sequence (x, f(x), f(f(x)), ...) *) -let iterate f x = - let rec iterate k x = k x; iterate k (f x) in - from_iter (fun k -> iterate k x) - -(** Sequence that calls the given function to produce elements *) -let forever f = - let rec forever k = k (f ()); forever k in - from_iter forever - -(** Cycle forever through the given sequence. O(n). *) -let cycle s = fun k -> while true do s k; done - -(** Consume the sequence, passing all its arguments to the function *) -let iter f seq = seq f - -(** Iterate on elements and their index in the sequence *) -let iteri f seq = - let r = ref 0 in - let k x = - f !r x; - incr r - in seq k - -(** Fold over elements of the sequence, consuming it *) -let fold f init seq = - let r = ref init in - seq (fun elt -> r := f !r elt); - !r - -(** Fold over elements of the sequence and their index, consuming it *) -let foldi f init seq = - let i = ref 0 in - let r = ref init in - seq (fun elt -> - r := f !r !i elt; - incr i); - !r - -(** Map objects of the sequence into other elements, lazily *) -let map f seq = - let seq_fun' k = seq (fun x -> k (f x)) in - seq_fun' - -(** Map objects, along with their index in the sequence *) -let mapi f seq = - let seq_fun' k = - let i = ref 0 in - seq (fun x -> k (f !i x); incr i) in - seq_fun' - -(** Filter on elements of the sequence *) -let filter p seq = - let seq_fun' k = seq (fun x -> if p x then k x) in - seq_fun' - -(** Append two sequences *) -let append s1 s2 = - let seq_fun k = s1 k; s2 k in - seq_fun - -(** Concatenate a sequence of sequences into one sequence *) -let concat s = - from_iter (fun k -> - (* function that is called on every sub-sequence *) - let k_seq seq = iter k seq in - s k_seq) - -let flatten s = concat s - -(** Monadic bind. It applies the function to every element of the - initial sequence, and calls [concat]. *) -let flatMap f seq = - from_iter - (fun k -> seq (fun x -> (f x) k)) - -let fmap f seq = - from_iter - (fun k -> - seq (fun x -> match f x with - | None -> () - | Some y -> k y)) - -(** Insert the given element between every element of the sequence *) -let intersperse elem seq = - fun k -> - let first = ref true in - seq (fun x -> (if !first then first := false else k elem); k x) - -(** Mutable unrolled list to serve as intermediate storage *) -module MList = struct - type 'a node = - | Nil - | Cons of 'a array * int ref * 'a node ref - - let of_seq seq = - let start = ref Nil in - let chunk_size = ref 8 in - (* fill the list. prev: tail-reference from previous node *) - let prev, cur = ref start, ref Nil in - seq - (fun x -> match !cur with - | Nil -> - let n = !chunk_size in - if n < 4096 then chunk_size := 2 * !chunk_size; - cur := Cons (Array.make n x, ref 1, ref Nil) - | Cons (a,n,next) -> - assert (!n < Array.length a); - a.(!n) <- x; - incr n; - if !n = Array.length a then begin - !prev := !cur; - prev := next; - cur := Nil - end - ); - !prev := !cur; - !start - - let rec iter f l = match l with - | Nil -> () - | Cons (a, n, tl) -> - for i=0 to !n - 1 do f a.(i) done; - iter f !tl - - let iteri f l = - let rec iteri i f l = match l with - | Nil -> () - | Cons (a, n, tl) -> - for j=0 to !n - 1 do f (i+j) a.(j) done; - iteri (i+ !n) f !tl - in iteri 0 f l - - let rec iter_rev f l = match l with - | Nil -> () - | Cons (a, n, tl) -> - iter_rev f !tl; - for i = !n-1 downto 0 do f a.(i) done - - let length l = - let rec len acc l = match l with - | Nil -> acc - | Cons (_, n, tl) -> len (acc+ !n) !tl - in len 0 l - - (** Get element by index *) - let rec get l i = match l with - | Nil -> raise (Invalid_argument "MList.get") - | Cons (a, n, _) when i < !n -> a.(i) - | Cons (_, n, tl) -> get !tl (i- !n) - - let to_seq l k = iter k l - - let _to_next arg l = - let cur = ref l in - let i = ref 0 in (* offset in cons *) - let rec get_next _ = match !cur with - | Nil -> None - | Cons (_, n, tl) when !i = !n -> - cur := !tl; - i := 0; - get_next arg - | Cons (a, n, _) -> - let x = a.(!i) in - incr i; - Some x - in get_next - - let to_gen l = _to_next () l - - let to_stream l = - Stream.from (_to_next 42 l) (* 42=magic cookiiiiiie *) -end - -(** Iterate on the sequence, storing elements in a data structure. - The resulting sequence can be iterated on as many times as needed. *) -let persistent seq = - let l = MList.of_seq seq in - MList.to_seq l - -(** Sort the sequence. Eager, O(n) ram and O(n ln(n)) time. *) -let sort ?(cmp=Pervasives.compare) seq = - (* use an intermediate list, then sort the list *) - let l = fold (fun l x -> x::l) [] seq in - let l = List.fast_sort cmp l in - fun k -> List.iter k l - -(** Group equal consecutive elements. *) -let group ?(eq=fun x y -> x = y) seq = - fun k -> - let cur = ref [] in - seq (fun x -> - match !cur with - | [] -> cur := [x] - | (y::_) as l when eq x y -> - cur := x::l (* [x] belongs to the group *) - | (_::_) as l -> - k l; (* yield group, and start another one *) - cur := [x]); - (* last list *) - if !cur <> [] then k !cur - -(** Remove consecutive duplicate elements. Basically this is - like [fun seq -> map List.hd (group seq)]. *) -let uniq ?(eq=fun x y -> x = y) seq = - fun k -> - let has_prev = ref false - and prev = ref (Obj.magic 0) in (* avoid option type, costly *) - seq (fun x -> - if !has_prev && eq !prev x - then () (* duplicate *) - else begin - has_prev := true; - prev := x; - k x - end) - -(** Sort the sequence and remove duplicates. Eager, same as [sort] *) -let sort_uniq ?(cmp=Pervasives.compare) seq = - let seq' = sort ~cmp seq in - uniq ~eq:(fun x y -> cmp x y = 0) seq' - -(** Cartesian product of the sequences. *) -let product outer inner = - let inner = persistent inner in - from_iter - (fun k -> - outer (fun x -> - inner (fun y -> k (x,y)))) - -(** [join ~join_row a b] combines every element of [a] with every - element of [b] using [join_row]. If [join_row] returns None, then - the two elements do not combine. Assume that [b] allows for multiple - iterations. *) -let join ~join_row s1 s2 = - fun k -> - s1 (fun a -> - s2 (fun b -> - match join_row a b with - | None -> () - | Some c -> k c)) (* yield the combination of [a] and [b] *) - -(** [unfoldr f b] will apply [f] to [b]. If it - yields [Some (x,b')] then [x] is returned - and unfoldr recurses with [b']. *) -let unfoldr f b = - let rec unfold k b = match f b with - | None -> () - | Some (x, b') -> k x; unfold k b' - in - from_iter (fun k -> unfold k b) - -(** Sequence of intermediate results *) -let scan f acc seq = - from_iter - (fun k -> - k acc; - let acc = ref acc in - seq (fun elt -> let acc' = f !acc elt in k acc'; acc := acc')) - -let max ?(lt=fun x y -> x < y) seq = - let ret = ref None in - seq (fun x -> match !ret with - | None -> ret := Some x - | Some y -> if lt y x then ret := Some x); - !ret - -let min ?(lt=fun x y -> x < y) seq = - let ret = ref None in - seq (fun x -> match !ret with - | None -> ret := Some x - | Some y -> if lt x y then ret := Some x); - !ret - -exception ExitSequence - -(** Take at most [n] elements from the sequence *) -let take n seq = - let count = ref 0 in - if n = 0 then empty - else fun k -> - try - seq (fun x -> - incr count; - k x; - if !count = n then raise ExitSequence) - with ExitSequence -> () - -(** Drop the [n] first elements of the sequence *) -let drop n seq = - let count = ref 0 in - fun k -> seq - (fun x -> if !count >= n then k x else incr count) - -(** Reverse the sequence. O(n) memory. *) -let rev seq = - let l = MList.of_seq seq in - from_iter (fun k -> MList.iter_rev k l) - -(** Do all elements satisfy the predicate? *) -let for_all p seq = - try - seq (fun x -> if not (p x) then raise ExitSequence); - true - with ExitSequence -> false - -(** Exists there some element satisfying the predicate? *) -let exists p seq = - try - seq (fun x -> if p x then raise ExitSequence); - false - with ExitSequence -> true - -(** How long is the sequence? *) -let length seq = - let r = ref 0 in - seq (fun _ -> incr r); - !r - -(** Is the sequence empty? *) -let is_empty seq = - try seq (fun _ -> raise ExitSequence); true - with ExitSequence -> false - -(** {2 Transform a sequence} *) - -let empty2 = - fun k -> () - -let is_empty2 seq2 = - try ignore (seq2 (fun _ _ -> raise ExitSequence)); true - with ExitSequence -> false - -let length2 seq2 = - let r = ref 0 in - seq2 (fun _ _ -> incr r); - !r - -let zip seq2 = - fun k -> seq2 (fun x y -> k (x,y)) - -let unzip seq = - fun k -> seq (fun (x,y) -> k x y) - -(** Zip elements of the sequence with their index in the sequence *) -let zip_i seq = - fun k -> - let r = ref 0 in - seq (fun x -> let n = !r in incr r; k n x) - -let fold2 f acc seq2 = - let acc = ref acc in - seq2 (fun x y -> acc := f !acc x y); - !acc - -let iter2 f seq2 = - seq2 f - -let map2 f seq2 = - fun k -> seq2 (fun x y -> k (f x y)) - -(** [map2_2 f g seq2] maps each [x, y] of seq2 into [f x y, g x y] *) -let map2_2 f g seq2 = - fun k -> seq2 (fun x y -> k (f x y) (g x y)) - -(** {2 Basic data structures converters} *) - -let to_list seq = List.rev (fold (fun y x -> x::y) [] seq) - -let to_rev_list seq = fold (fun y x -> x :: y) [] seq - (** Get the list of the reversed sequence (more efficient) *) - -let of_list l = from_iter (fun k -> List.iter k l) - -let to_array seq = - let l = MList.of_seq seq in - let n = MList.length l in - if n = 0 - then [||] - else begin - let a = Array.make n (MList.get l 0) in - MList.iteri (fun i x -> a.(i) <- x) l; - a - end - -let of_array a = - fun k -> - for i = 0 to Array.length a - 1 do - k (Array.unsafe_get a i) - done - -let of_array_i a = - fun k -> - for i = 0 to Array.length a - 1 do - k (i, Array.unsafe_get a i) - done - -let of_array2 a = - fun k -> - for i = 0 to Array.length a - 1 do - k i (Array.unsafe_get a i) - done - -(** [array_slice a i j] Sequence of elements whose indexes range - from [i] to [j] *) -let array_slice a i j = - assert (i >= 0 && j < Array.length a); - fun k -> - for idx = i to j do - k a.(idx); (* iterate on sub-array *) - done - -(** Sequence of elements of a stream (usable only once) *) -let of_stream s = - let seq k = Stream.iter k s in - from_iter seq - -(** Convert to a stream. The sequence is made persistent. *) -let to_stream seq = - let l = MList.of_seq seq in - MList.to_stream l - -(** Push elements of the sequence on the stack *) -let to_stack s seq = iter (fun x -> Stack.push x s) seq - -(** Sequence of elements of the stack (same order as [Stack.iter]) *) -let of_stack s = from_iter (fun k -> Stack.iter k s) - -(** Push elements of the sequence into the queue *) -let to_queue q seq = iter (fun x -> Queue.push x q) seq - -(** Sequence of elements contained in the queue, FIFO order *) -let of_queue q = from_iter (fun k -> Queue.iter k q) - -let hashtbl_add h seq = - iter (fun (k,v) -> Hashtbl.add h k v) seq - -let hashtbl_replace h seq = - iter (fun (k,v) -> Hashtbl.replace h k v) seq - -let to_hashtbl seq = - let h = Hashtbl.create 3 in - hashtbl_replace h seq; - h - -let to_hashtbl2 seq2 = - let h = Hashtbl.create 3 in - seq2 (fun k v -> Hashtbl.replace h k v); - h - -let of_hashtbl h = - from_iter (fun k -> Hashtbl.iter (fun a b -> k (a, b)) h) - -let of_hashtbl2 h = - fun k -> Hashtbl.iter k h - -let hashtbl_keys h = - from_iter (fun k -> Hashtbl.iter (fun a b -> k a) h) - -let hashtbl_values h = - from_iter (fun k -> Hashtbl.iter (fun a b -> k b) h) - -let of_str s = from_iter (fun k -> String.iter k s) - -let to_str seq = - let b = Buffer.create 64 in - iter (fun c -> Buffer.add_char b c) seq; - Buffer.contents b - -let of_in_channel ic = - from_iter (fun k -> - try while true do - let c = input_char ic in k c - done with End_of_file -> ()) - -(** Copy content of the sequence into the buffer *) -let to_buffer seq buf = - iter (fun c -> Buffer.add_char buf c) seq - -(** Iterator on integers in [start...stop] by steps 1 *) -let int_range ~start ~stop = - fun k -> - for i = start to stop do k i done - -let int_range_dec ~start ~stop = - fun k -> - for i = start downto stop do k i done - -(** Convert the given set to a sequence. The set module must be provided. *) -let of_set (type s) (type v) m set = - let module S = (val m : Set.S with type t = s and type elt = v) in - from_iter - (fun k -> S.iter k set) - -(** Convert the sequence to a set, given the proper set module *) -let to_set (type s) (type v) m seq = - let module S = (val m : Set.S with type t = s and type elt = v) in - fold - (fun set x -> S.add x set) - S.empty seq - -type 'a gen = unit -> 'a option - -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_seq iter1 in - MList.to_seq l - -let to_gen seq = - let l = MList.of_seq seq in - MList.to_gen l - -(** {2 Functorial conversions between sets and sequences} *) - -module Set = struct - module type S = sig - include Set.S - val of_seq : elt sequence -> t - val to_seq : t -> elt sequence - end - - (** Create an enriched Set module from the given one *) - module Adapt(X : Set.S) = struct - let to_seq set = from_iter (fun k -> X.iter k set) - - let of_seq seq = fold (fun set x -> X.add x set) X.empty seq - - include X - end - - (** Functor to build an extended Set module from an ordered type *) - module Make(X : Set.OrderedType) = struct - module MySet = Set.Make(X) - include Adapt(MySet) - end -end - -(** {2 Conversion between maps and sequences.} *) - -module Map = struct - module type S = sig - include Map.S - val to_seq : 'a t -> (key * 'a) sequence - val of_seq : (key * 'a) sequence -> 'a t - val keys : 'a t -> key sequence - val values : 'a t -> 'a sequence - end - - (** Adapt a pre-existing Map module to make it sequence-aware *) - module Adapt(M : Map.S) = struct - let to_seq m = from_iter (fun k -> M.iter (fun x y -> k (x,y)) m) - - let of_seq seq = fold (fun m (k,v) -> M.add k v m) M.empty seq - - let keys m = from_iter (fun k -> M.iter (fun x _ -> k x) m) - - let values m = from_iter (fun k -> M.iter (fun _ y -> k y) m) - - include M - end - - (** Create an enriched Map module, with sequence-aware functions *) - module Make(V : Map.OrderedType) : S with type key = V.t = struct - module M = Map.Make(V) - include Adapt(M) - end -end - -(** {2 Infinite sequences of random values} *) - -let random_int bound = forever (fun () -> Random.int bound) - -let random_bool = forever Random.bool - -let random_float bound = forever (fun () -> Random.float bound) - -(** Sequence of choices of an element in the array *) -let random_array a = - assert (Array.length a > 0); - let seq k = - while true do - let i = Random.int (Array.length a) in - k a.(i); - done in - from_iter seq - -let random_list l = random_array (Array.of_list l) - -(** {2 Infix functions} *) - -module Infix = struct - let (--) i j = int_range ~start:i ~stop:j - - let (--^) i j = int_range_dec ~start:i ~stop:j -end - -include Infix - -(** {2 Pretty printing of sequences} *) - -(** Pretty print a sequence of ['a], using the given pretty printer - to print each elements. An optional separator string can be provided. *) -let print ?(start="") ?(stop="") ?(sep=", ") pp_elt formatter seq = - let first = ref true in - Format.pp_print_string formatter start; - iter - (fun x -> - (if !first then first := false - else begin - Format.pp_print_string formatter sep; - Format.pp_print_cut formatter (); - end); - pp_elt formatter x) - seq; - Format.pp_print_string formatter stop; - () - -let pp ?(start="") ?(stop="") ?(sep=", ") pp_elt buf seq = - let first = ref true in - Buffer.add_string buf start; - iter - (fun x -> - if !first then first := false else Buffer.add_string buf sep; - pp_elt buf x) - seq; - Buffer.add_string buf stop; - () - -let to_string ?start ?stop ?sep pp_elt seq = - let buf = Buffer.create 25 in - pp ?start ?stop ?sep pp_elt buf seq; - Buffer.contents buf diff --git a/core/CCSequence.ml b/core/CCSequence.ml new file mode 120000 index 00000000..397a44e3 --- /dev/null +++ b/core/CCSequence.ml @@ -0,0 +1 @@ +../sequence/sequence.ml \ No newline at end of file diff --git a/core/CCSequence.mli b/core/CCSequence.mli index b6e1a4a4..3b2056d3 100644 --- a/core/CCSequence.mli +++ b/core/CCSequence.mli @@ -23,16 +23,16 @@ 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 Transient iterators, that abstract on a finite sequence of elements.} *) +(** {1 Simple and Efficient Iterators} *) (** The iterators are designed to allow easy transfer (mappings) between data - structures, without defining n^2 conversions between the n types. The + structures, without defining [n^2] conversions between the [n] types. The implementation relies on the assumption that a sequence can be iterated on as many times as needed; this choice allows for high performance of many combinators. However, for transient iterators, the {!persistent} function is provided, storing elements of a transient iterator in memory; the iterator can then be used several times (See further). - + Note that some combinators also return sequences (e.g. {!group}). The transformation is computed on the fly every time one iterates over the resulting sequence. If a transformation performs heavy computation, @@ -42,7 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. until their result is iterated on. For instance, if one calls {!map} on a sequence, one gets a new sequence, but nothing else happens until this new sequence is used (by folding or iterating on it). - + If a sequence is built from an iteration function that is {b repeatable} (i.e. calling it several times always iterates on the same set of elements, for instance List.iter or Map.iter), then @@ -53,8 +53,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. of this memory structure, cheaply and repeatably. *) type +'a t = ('a -> unit) -> unit - (** Sequence iterator type, representing a finite sequence of values - of type ['a] that one can iterate on. *) + (** A sequence of values of type ['a]. If you give it a function ['a -> unit] + it will be applied to every element of the sequence successively. *) type +'a sequence = 'a t @@ -76,12 +76,34 @@ val empty : 'a t val singleton : 'a -> 'a t (** Singleton sequence, with exactly one element. *) +val doubleton : 'a -> 'a -> 'a t + (** Sequence with exactly two elements + @since NEXT_RELEASE *) + +val cons : 'a -> 'a t -> 'a t + (** [cons x l] yields [x], then yields from [l]. + Same as [append (singleton x) l] + @since NEXT_RELEASE *) + + +val snoc : 'a t -> 'a -> 'a t + (** Same as {!cons} but yields the element after iterating on [l] + @since NEXT_RELEASE *) + +val return : 'a -> 'a t + (** Synonym to {!singleton} + @since NEXT_RELEASE *) + +val pure : 'a -> 'a t + (** Synonym to {!singleton} + @since NEXT_RELEASE *) + val repeat : 'a -> 'a t (** Infinite sequence of the same element. You may want to look - at {!take} if you iterate on it. *) + at {!take} and the likes if you iterate on it. *) val iterate : ('a -> 'a) -> 'a -> 'a t - (** [iterate f x] is the infinite sequence (x, f(x), f(f(x)), ...) *) + (** [iterate f x] is the infinite sequence [x, f(x), f(f(x)), ...] *) val forever : (unit -> 'b) -> 'b t (** Sequence that calls the given function to produce elements. @@ -97,7 +119,8 @@ val cycle : 'a t -> 'a t (** {2 Consume a sequence} *) val iter : ('a -> unit) -> 'a t -> unit - (** Consume the sequence, passing all its arguments to the function *) + (** Consume the sequence, passing all its arguments to the function. + Basically [iter f seq] is just [seq f]. *) val iteri : (int -> 'a -> unit) -> 'a t -> unit (** Iterate on elements and their index in the sequence *) @@ -120,6 +143,15 @@ val for_all : ('a -> bool) -> 'a t -> bool val exists : ('a -> bool) -> 'a t -> bool (** Exists there some element satisfying the predicate? *) +val mem : ?eq:('a -> 'a -> bool) -> 'a -> 'a t -> bool + (** Is the value a member of the sequence? + @param eq the equality predicate to use (default [(=)]) + @since NEXT_RELEASE *) + +val find : ('a -> 'b option) -> 'a t -> 'b option + (** Find the first element on which the function doesn't return [None] + @since NEXT_RELEASE *) + val length : 'a t -> int (** How long is the sequence? Forces the sequence. *) @@ -145,18 +177,43 @@ val flatMap : ('a -> 'b t) -> 'a t -> 'b t (** Monadic bind. Intuitively, it applies the function to every element of the initial sequence, and calls {!concat}. *) +val flat_map : ('a -> 'b t) -> 'a t -> 'b t + (** Alias to {!flatMap} with a more explicit name + @since NEXT_RELEASE *) + val fmap : ('a -> 'b option) -> 'a t -> 'b t (** Specialized version of {!flatMap} for options. *) +val filter_map : ('a -> 'b option) -> 'a t -> 'b t + (** Alias to {!fmap} with a more explicit name + @since NEXT_RELEASE *) + val intersperse : 'a -> 'a t -> 'a t (** Insert the single element between every element of the sequence *) +(** {2 Caching} *) + val persistent : 'a t -> 'a t - (** Iterate on the sequence, storing elements in a data structure. + (** Iterate on the sequence, storing elements in an efficient internal structure.. The resulting sequence can be iterated on as many times as needed. {b Note}: calling persistent on an already persistent sequence will still make a new copy of the sequence! *) +val persistent_lazy : 'a t -> 'a t + (** Lazy version of {!persistent}. When calling [persistent_lazy s], + a new sequence [s'] is immediately returned (without actually consuming + [s]) in constant time; the first time [s'] is iterated on, + it also consumes [s] and caches its content into a inner data + structure that will back [s'] for future iterations. + + {b warning}: on the first traversal of [s'], if the traversal + is interrupted prematurely ({!take}, etc.) then [s'] will not be + memorized, and the next call to [s'] will traverse [s] again. + + @since NEXT_RELEASE *) + +(** {2 Misc} *) + val sort : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t (** Sort the sequence. Eager, O(n) ram and O(n ln(n)) time. It iterates on elements of the argument sequence immediately, @@ -173,9 +230,14 @@ val uniq : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t like [fun seq -> map List.hd (group seq)]. *) val product : 'a t -> 'b t -> ('a * 'b) t - (** Cartesian product of the sequences. The first one is transformed - by calling [persistent] on it, so that it can be traversed - several times (outer loop of the product) *) + (** Cartesian product of the sequences. When calling [product a b], + the caller {b MUST} ensure that [b] can be traversed as many times + as required (several times), possibly by calling {!persistent} on it + beforehand. *) + +val product2 : 'a t -> 'b t -> ('a, 'b) t2 + (** Binary version of {!product}. Same requirements. + @since NEXT_RELEASE *) val join : join_row:('a -> 'b -> 'c option) -> 'a t -> 'b t -> 'c t (** [join ~join_row a b] combines every element of [a] with every @@ -183,7 +245,7 @@ val join : join_row:('a -> 'b -> 'c option) -> 'a t -> 'b t -> 'c t the two elements do not combine. Assume that [b] allows for multiple iterations. *) -val unfoldr : ('b -> ('a * 'b) option) -> 'b -> 'a t +val unfoldr : ('b -> ('a * 'b) option) -> 'b -> 'a t (** [unfoldr f b] will apply [f] to [b]. If it yields [Some (x,b')] then [x] is returned and unfoldr recurses with [b']. *) @@ -200,13 +262,32 @@ val min : ?lt:('a -> 'a -> bool) -> 'a t -> 'a option (** Min element of the sequence, using the given comparison function. see {!max} for more details. *) +val head : 'a t -> 'a option + (** First element, if any, otherwise [None] + @since NEXT_RELEASE *) + +val head_exn : 'a t -> 'a + (** First element, if any, fails + @raise Invalid_argument if the sequence is empty + @since NEXT_RELEASE *) + val take : int -> 'a t -> 'a t (** Take at most [n] elements from the sequence. Works on infinite sequences. *) +val take_while : ('a -> bool) -> 'a t -> 'a t + (** Take elements while they satisfy the predicate, then stops iterating. + Will work on an infinite sequence [s] if the predicate is false for at + least one element of [s]. + @since NEXT_RELEASE *) + val drop : int -> 'a t -> 'a t (** Drop the [n] first elements of the sequence. Lazy. *) +val drop_while : ('a -> bool) -> 'a t -> 'a t + (** Predicate version of {!drop} + @since NEXT_RELEASE *) + val rev : 'a t -> 'a t (** Reverse the sequence. O(n) memory and time, needs the sequence to be finite. The result is persistent and does @@ -239,15 +320,22 @@ val map2_2 : ('a -> 'b -> 'c) -> ('a -> 'b -> 'd) -> ('a, 'b) t2 -> ('c, 'd) t2 (** {2 Basic data structures converters} *) val to_list : 'a t -> 'a list + (** Convert the sequence into a list. Preserves order of elements. + This function is tail-recursive, but consumes 2*n memory. + If order doesn't matter to you, consider {!to_rev_list}. *) val to_rev_list : 'a t -> 'a list (** Get the list of the reversed sequence (more efficient than {!to_list}) *) val of_list : 'a list -> 'a t +val to_opt : 'a t -> 'a option + (** Alias to {!head} + @since NEXT_RELEASE *) + val to_array : 'a t -> 'a array (** Convert to an array. Currently not very efficient because - and intermediate list is used. *) + an intermediate list is used. *) val of_array : 'a array -> 'a t @@ -260,6 +348,10 @@ val array_slice : 'a array -> int -> int -> 'a t (** [array_slice a i j] Sequence of elements whose indexes range from [i] to [j] *) +val of_opt : 'a option -> 'a t + (** Iterate on 0 or 1 values. + @since NEXT_RELEASE *) + val of_stream : 'a Stream.t -> 'a t (** Sequence of elements of a stream (usable only once) *) @@ -304,10 +396,20 @@ val hashtbl_values : ('a, 'b) Hashtbl.t -> 'b t val of_str : string -> char t val to_str : char t -> string +val concat_str : string t -> string + (** Concatenate strings together, eagerly. + Also see {!intersperse} to add a separator. + @since NEXT_RELEASE *) + +exception OneShotSequence + (** Raised when the user tries to iterate several times on + a transient iterator *) + val of_in_channel : in_channel -> char t (** Iterates on characters of the input (can block when one iterates over the sequence). If you need to iterate - several times on this sequence, use {!persistent}. *) + several times on this sequence, use {!persistent}. + @raise OneShotSequence when used more than once. *) val to_buffer : char t -> Buffer.t -> unit (** Copy content of the sequence into the buffer *) @@ -327,6 +429,7 @@ val to_set : (module Set.S with type elt = 'a and type t = 'b) -> 'a t -> 'b (** Convert the sequence 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 a sequence from it *) @@ -334,6 +437,12 @@ val of_gen : 'a gen -> 'a t val to_gen : 'a t -> 'a gen (** Make the sequence 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 sequence persistent and then iterate on it. Eager. *) + (** {2 Functorial conversions between sets and sequences} *) module Set : sig @@ -341,11 +450,17 @@ module Set : sig include Set.S val of_seq : elt sequence -> t val to_seq : t -> elt sequence + + val to_list : t -> elt list + (** @since NEXT_RELEASE *) + + val of_list : elt list -> t + (** @since NEXT_RELEASE *) end (** Create an enriched Set module from the given one *) module Adapt(X : Set.S) : S with type elt = X.elt and type t = X.t - + (** Functor to build an extended Set module from an ordered type *) module Make(X : Set.OrderedType) : S with type elt = X.t end @@ -359,6 +474,12 @@ module Map : sig val of_seq : (key * 'a) sequence -> 'a t val keys : 'a t -> key sequence val values : 'a t -> 'a sequence + + val to_list : 'a t -> (key * 'a) list + (** @since NEXT_RELEASE *) + + val of_list : (key * 'a) list -> 'a t + (** @since NEXT_RELEASE *) end (** Adapt a pre-existing Map module to make it sequence-aware *) @@ -390,26 +511,95 @@ val random_list : 'a list -> 'a t module Infix : sig val (--) : int -> int -> int t + (** [a -- b] is the range of integers from [a] to [b], both included, + in increasing order. It will therefore be empty if [a > b]. *) val (--^) : int -> int -> int t (** [a --^ b] is the range of integers from [b] to [a], both included, in decreasing order (starts from [a]). It will therefore be empty if [a < b]. *) + + val (>>=) : 'a t -> ('a -> 'b t) -> 'b t + (** Monadic bind (infix version of {!flat_map} + @since NEXT_RELEASE *) + + val (>|=) : 'a t -> ('a -> 'b) -> 'b t + (** Infix version of {!map} + @since NEXT_RELEASE *) + + val (<*>) : ('a -> 'b) t -> 'a t -> 'b t + (** Applicative operator (product+application) + @since NEXT_RELEASE *) + + val (<+>) : 'a t -> 'a t -> 'a t + (** Concatenation of sequences + @since NEXT_RELEASE *) end include module type of Infix + (** {2 Pretty printing of sequences} *) -val print : ?start:string -> ?stop:string -> ?sep:string -> - (Format.formatter -> 'a -> unit) -> +val pp_seq : ?sep:string -> (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit (** Pretty print a sequence of ['a], using the given pretty printer to print each elements. An optional separator string can be provided. *) -val pp : ?start:string -> ?stop:string -> ?sep:string -> - (Buffer.t -> 'a -> unit) -> - Buffer.t -> 'a t -> unit +val pp_buf : ?sep:string -> (Buffer.t -> 'a -> unit) -> + Buffer.t -> 'a t -> unit + (** Print into a buffer *) -val to_string : ?start:string -> ?stop:string -> ?sep:string -> - (Buffer.t -> 'a -> unit) -> 'a t -> string +val to_string : ?sep:string -> ('a -> string) -> 'a t -> string + (** Print into a string *) + +(** {2 Basic IO} + +Very basic interface to manipulate files as sequence of chunks/lines. The +sequences take care of opening and closing files properly; every time +one iterates over a sequence, the file is opened/closed again. + +Example: copy a file ["a"] into file ["b"], removing blank lines: + +{[ + Sequence.(IO.lines_of "a" |> filter (fun l-> l<> "") |> IO.write_lines "b");; +]} + +By chunks of [4096] bytes: + +{[ + Sequence.IO.(chunks_of ~size:4096 "a" |> write_to "b");; +]} + +@since NEXT_RELEASE *) + +module IO : sig + val lines_of : ?mode:int -> ?flags:open_flag list -> + string -> string t + (** [lines_of filename] reads all lines of the given file. It raises the + same exception as would opening the file and read from it, except + from [End_of_file] (which is caught). The file is {b always} properly + closed. + Every time the sequence is iterated on, the file is opened again, so + different iterations might return different results + @param mode default [0o644] + @param flags default: [[Open_rdonly]] *) + + val chunks_of : ?mode:int -> ?flags:open_flag list -> ?size:int -> + string -> string t + (** Read chunks of the given [size] from the file. The last chunk might be + smaller. Behaves like {!lines_of} regarding errors and options. + Every time the sequence is iterated on, the file is opened again, so + different iterations might return different results *) + + val write_to : ?mode:int -> ?flags:open_flag list -> + string -> string t -> unit + (** [write_to filename seq] writes all strings from [seq] into the given + file. It takes care of opening and closing the file. + @param mode default [0o644] + @param flags used by [open_out_gen]. Default: [[Open_creat;Open_wronly]]. *) + + val write_lines : ?mode:int -> ?flags:open_flag list -> + string -> string t -> unit + (** Same as {!write_to}, but intercales ['\n'] between each string *) +end