CCSequence now shares code with the 'sequence' library; merged the .mli so it reflects versions properly

This commit is contained in:
Simon Cruanes 2014-08-08 20:26:04 +02:00
parent bb64cc9a6d
commit d638038089
2 changed files with 215 additions and 715 deletions

View file

@ -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

1
core/CCSequence.ml Symbolic link
View file

@ -0,0 +1 @@
../sequence/sequence.ml

View file

@ -23,10 +23,10 @@ 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. 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 (** 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 implementation relies on the assumption that a sequence can be iterated
on as many times as needed; this choice allows for high performance on as many times as needed; this choice allows for high performance
of many combinators. However, for transient iterators, the {!persistent} of many combinators. However, for transient iterators, the {!persistent}
@ -53,8 +53,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
of this memory structure, cheaply and repeatably. *) of this memory structure, cheaply and repeatably. *)
type +'a t = ('a -> unit) -> unit type +'a t = ('a -> unit) -> unit
(** Sequence iterator type, representing a finite sequence of values (** A sequence of values of type ['a]. If you give it a function ['a -> unit]
of type ['a] that one can iterate on. *) it will be applied to every element of the sequence successively. *)
type +'a sequence = 'a t type +'a sequence = 'a t
@ -76,12 +76,34 @@ val empty : 'a t
val singleton : 'a -> 'a t val singleton : 'a -> 'a t
(** Singleton sequence, with exactly one element. *) (** 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 val repeat : 'a -> 'a t
(** Infinite sequence of the same element. You may want to look (** 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 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 val forever : (unit -> 'b) -> 'b t
(** Sequence that calls the given function to produce elements. (** Sequence that calls the given function to produce elements.
@ -97,7 +119,8 @@ val cycle : 'a t -> 'a t
(** {2 Consume a sequence} *) (** {2 Consume a sequence} *)
val iter : ('a -> unit) -> 'a t -> unit 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 val iteri : (int -> 'a -> unit) -> 'a t -> unit
(** Iterate on elements and their index in the sequence *) (** 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 val exists : ('a -> bool) -> 'a t -> bool
(** Exists there some element satisfying the predicate? *) (** 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 val length : 'a t -> int
(** How long is the sequence? Forces the sequence. *) (** 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 (** Monadic bind. Intuitively, it applies the function to every element of the
initial sequence, and calls {!concat}. *) 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 val fmap : ('a -> 'b option) -> 'a t -> 'b t
(** Specialized version of {!flatMap} for options. *) (** 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 val intersperse : 'a -> 'a t -> 'a t
(** Insert the single element between every element of the sequence *) (** Insert the single element between every element of the sequence *)
(** {2 Caching} *)
val persistent : 'a t -> 'a t 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. The resulting sequence can be iterated on as many times as needed.
{b Note}: calling persistent on an already persistent sequence {b Note}: calling persistent on an already persistent sequence
will still make a new copy of the 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 val sort : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t
(** Sort the sequence. Eager, O(n) ram and O(n ln(n)) time. (** Sort the sequence. Eager, O(n) ram and O(n ln(n)) time.
It iterates on elements of the argument sequence immediately, 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)]. *) like [fun seq -> map List.hd (group seq)]. *)
val product : 'a t -> 'b t -> ('a * 'b) t val product : 'a t -> 'b t -> ('a * 'b) t
(** Cartesian product of the sequences. The first one is transformed (** Cartesian product of the sequences. When calling [product a b],
by calling [persistent] on it, so that it can be traversed the caller {b MUST} ensure that [b] can be traversed as many times
several times (outer loop of the product) *) 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 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 (** [join ~join_row a b] combines every element of [a] with every
@ -200,13 +262,32 @@ val min : ?lt:('a -> 'a -> bool) -> 'a t -> 'a option
(** Min element of the sequence, using the given comparison function. (** Min element of the sequence, using the given comparison function.
see {!max} for more details. *) 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 val take : int -> 'a t -> 'a t
(** Take at most [n] elements from the sequence. Works on infinite (** Take at most [n] elements from the sequence. Works on infinite
sequences. *) 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 val drop : int -> 'a t -> 'a t
(** Drop the [n] first elements of the sequence. Lazy. *) (** 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 val rev : 'a t -> 'a t
(** Reverse the sequence. O(n) memory and time, needs the (** Reverse the sequence. O(n) memory and time, needs the
sequence to be finite. The result is persistent and does 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} *) (** {2 Basic data structures converters} *)
val to_list : 'a t -> 'a list 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 val to_rev_list : 'a t -> 'a list
(** Get the list of the reversed sequence (more efficient than {!to_list}) *) (** Get the list of the reversed sequence (more efficient than {!to_list}) *)
val of_list : 'a list -> 'a t 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 val to_array : 'a t -> 'a array
(** Convert to an array. Currently not very efficient because (** 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 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 (** [array_slice a i j] Sequence of elements whose indexes range
from [i] to [j] *) 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 val of_stream : 'a Stream.t -> 'a t
(** Sequence of elements of a stream (usable only once) *) (** 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 of_str : string -> char t
val to_str : char t -> string 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 val of_in_channel : in_channel -> char t
(** Iterates on characters of the input (can block when one (** Iterates on characters of the input (can block when one
iterates over the sequence). If you need to iterate 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 val to_buffer : char t -> Buffer.t -> unit
(** Copy content of the sequence into the buffer *) (** 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 *) (** Convert the sequence to a set, given the proper set module *)
type 'a gen = unit -> 'a option type 'a gen = unit -> 'a option
type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist]
val of_gen : 'a gen -> 'a t val of_gen : 'a gen -> 'a t
(** Traverse eagerly the generator and build a sequence from it *) (** 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 val to_gen : 'a t -> 'a gen
(** Make the sequence persistent (O(n)) and then iterate on it. Eager. *) (** 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} *) (** {2 Functorial conversions between sets and sequences} *)
module Set : sig module Set : sig
@ -341,6 +450,12 @@ module Set : sig
include Set.S include Set.S
val of_seq : elt sequence -> t val of_seq : elt sequence -> t
val to_seq : t -> elt sequence 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 end
(** Create an enriched Set module from the given one *) (** Create an enriched Set module from the given one *)
@ -359,6 +474,12 @@ module Map : sig
val of_seq : (key * 'a) sequence -> 'a t val of_seq : (key * 'a) sequence -> 'a t
val keys : 'a t -> key sequence val keys : 'a t -> key sequence
val values : 'a t -> 'a 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 end
(** Adapt a pre-existing Map module to make it sequence-aware *) (** 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 module Infix : sig
val (--) : int -> int -> int t 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 val (--^) : int -> int -> int t
(** [a --^ b] is the range of integers from [b] to [a], both included, (** [a --^ b] is the range of integers from [b] to [a], both included,
in decreasing order (starts from [a]). in decreasing order (starts from [a]).
It will therefore be empty if [a < b]. *) 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 end
include module type of Infix include module type of Infix
(** {2 Pretty printing of sequences} *) (** {2 Pretty printing of sequences} *)
val print : ?start:string -> ?stop:string -> ?sep:string -> val pp_seq : ?sep:string -> (Format.formatter -> 'a -> unit) ->
(Format.formatter -> 'a -> unit) ->
Format.formatter -> 'a t -> unit Format.formatter -> 'a t -> unit
(** Pretty print a sequence of ['a], using the given pretty printer (** Pretty print a sequence of ['a], using the given pretty printer
to print each elements. An optional separator string can be provided. *) to print each elements. An optional separator string can be provided. *)
val pp : ?start:string -> ?stop:string -> ?sep:string -> val pp_buf : ?sep:string -> (Buffer.t -> 'a -> unit) ->
(Buffer.t -> 'a -> unit) ->
Buffer.t -> 'a t -> unit Buffer.t -> 'a t -> unit
(** Print into a buffer *)
val to_string : ?start:string -> ?stop:string -> ?sep:string -> val to_string : ?sep:string -> ('a -> string) -> 'a t -> string
(Buffer.t -> 'a -> unit) -> '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