diff --git a/.merlin b/.merlin index a047e25..68e740a 100644 --- a/.merlin +++ b/.merlin @@ -7,4 +7,4 @@ B _build/bench/ PKG oUnit qcheck PKG benchmark FLG -safe-string -FLG -w +a -w -4 -w -44 +FLG -w+a-4-44-48-60@8 diff --git a/Makefile b/Makefile index b91e3ed..93770f4 100644 --- a/Makefile +++ b/Makefile @@ -97,6 +97,7 @@ release: watch: while find src/ -print0 | xargs -0 inotifywait -e delete_self -e modify ; do \ echo "============ at `date` ==========" ; \ + sleep 0.2; \ make all; \ done diff --git a/_oasis b/_oasis index ce827cf..d0a407a 100644 --- a/_oasis +++ b/_oasis @@ -1,6 +1,6 @@ OASISFormat: 0.4 Name: sequence -Version: 0.10 +Version: 0.11 Homepage: https://github.com/c-cube/sequence Authors: Simon Cruanes License: BSD-2-clause diff --git a/_tags b/_tags index 80091d0..041c8f7 100644 --- a/_tags +++ b/_tags @@ -50,8 +50,9 @@ true: annot, bin_annot : pkg_bytes : use_sequence # OASIS_STOP -true: bin_annot -<**/*.ml>: warn_A, warn(-4) +true: safe_string, bin_annot, color(always) +<**/*.ml>: warn(+a-4-44-48@8) +: warn(-33) true: mark_tag_used <**/*.cmx>: optimize(3) -: nolabels +: nolabels diff --git a/descr b/descr deleted file mode 100644 index 25f3a49..0000000 --- a/descr +++ /dev/null @@ -1,6 +0,0 @@ -Simple and lightweight sequence abstract data type. - -Simple sequence abstract data type, intended to transfer a finite number of -elements from one data structure to another. Some transformations on sequences, -like `filter`, `map`, `take`, `drop` and `append` can be performed before the -sequence is iterated/folded on. diff --git a/myocamlbuild.ml b/myocamlbuild.ml index dbc5add..1aa68cd 100644 --- a/myocamlbuild.ml +++ b/myocamlbuild.ml @@ -1,5 +1,5 @@ (* OASIS_START *) -(* DO NOT EDIT (digest: 25607cca926d807aaffd1aa7d72d57d9) *) +(* DO NOT EDIT (digest: df4781680e858ab0acccf45efeb50c19) *) module OASISGettext = struct (* # 22 "src/oasis/OASISGettext.ml" *) @@ -105,10 +105,7 @@ module OASISString = struct ok := false; incr str_idx done; - if !what_idx = String.length what then - true - else - false + !what_idx = String.length what let strip_starts_with ~what str = @@ -131,10 +128,7 @@ module OASISString = struct ok := false; decr str_idx done; - if !what_idx = -1 then - true - else - false + !what_idx = -1 let strip_ends_with ~what str = @@ -440,7 +434,7 @@ module OASISExpr = struct end -# 443 "myocamlbuild.ml" +# 437 "myocamlbuild.ml" module BaseEnvLight = struct (* # 22 "src/base/BaseEnvLight.ml" *) @@ -520,7 +514,7 @@ module BaseEnvLight = struct end -# 523 "myocamlbuild.ml" +# 517 "myocamlbuild.ml" module MyOCamlbuildFindlib = struct (* # 22 "src/plugins/ocamlbuild/MyOCamlbuildFindlib.ml" *) @@ -881,7 +875,7 @@ module MyOCamlbuildBase = struct end -# 884 "myocamlbuild.ml" +# 878 "myocamlbuild.ml" open Ocamlbuild_plugin;; let package_default = { @@ -907,6 +901,6 @@ let conf = {MyOCamlbuildFindlib.no_automatic_syntax = false} let dispatch_default = MyOCamlbuildBase.dispatch_default conf package_default;; -# 911 "myocamlbuild.ml" +# 905 "myocamlbuild.ml" (* OASIS_STOP *) Ocamlbuild_plugin.dispatch dispatch_default;; diff --git a/opam b/opam index 9f3cdf6..f3bb2b5 100644 --- a/opam +++ b/opam @@ -1,13 +1,14 @@ opam-version: "1.2" name: "sequence" -version: "0.10" +version: "0.11" author: "Simon Cruanes" -maintainer: "simon.cruanes@inria.fr" +maintainer: "simon.cruanes.2007@m4x.org" license: "BSD-2-clauses" build: [ ["./configure" "--disable-docs" "--%{delimcc:enable}%-invert" "--%{base-bigarray:enable}%-bigarray" + "--prefix" "%{prefix}%" ] [make "build"] ] diff --git a/sequence.mldylib b/sequence.mldylib deleted file mode 100644 index 52e69a0..0000000 --- a/sequence.mldylib +++ /dev/null @@ -1,5 +0,0 @@ -# OASIS_START -# DO NOT EDIT (digest: 8c0ffebbdb3e063d4b3e5cc00517b199) -Sequence -SequenceLabels -# OASIS_STOP diff --git a/sequence.mllib b/sequence.mllib deleted file mode 100644 index 52e69a0..0000000 --- a/sequence.mllib +++ /dev/null @@ -1,5 +0,0 @@ -# OASIS_START -# DO NOT EDIT (digest: 8c0ffebbdb3e063d4b3e5cc00517b199) -Sequence -SequenceLabels -# OASIS_STOP diff --git a/setup.ml b/setup.ml index 58904ac..7fcafd3 100644 --- a/setup.ml +++ b/setup.ml @@ -1,9 +1,9 @@ (* setup.ml generated for the first time by OASIS v0.4.4 *) (* OASIS_START *) -(* DO NOT EDIT (digest: b6facd5b08b6b1360edc26bd90d50fa3) *) +(* DO NOT EDIT (digest: b51801b110892305c8a99f1b01e7fcf0) *) (* - Regenerated by OASIS v0.4.8 + Regenerated by OASIS v0.4.10 Visit http://oasis.forge.ocamlcore.org for more information and documentation about functions used in this file. *) @@ -112,10 +112,7 @@ module OASISString = struct ok := false; incr str_idx done; - if !what_idx = String.length what then - true - else - false + !what_idx = String.length what let strip_starts_with ~what str = @@ -138,10 +135,7 @@ module OASISString = struct ok := false; decr str_idx done; - if !what_idx = -1 then - true - else - false + !what_idx = -1 let strip_ends_with ~what str = @@ -3162,7 +3156,7 @@ module OASISFileUtil = struct end -# 3165 "setup.ml" +# 3159 "setup.ml" module BaseEnvLight = struct (* # 22 "src/base/BaseEnvLight.ml" *) @@ -3242,7 +3236,7 @@ module BaseEnvLight = struct end -# 3245 "setup.ml" +# 3239 "setup.ml" module BaseContext = struct (* # 22 "src/base/BaseContext.ml" *) @@ -5665,7 +5659,7 @@ module BaseCompat = struct end -# 5668 "setup.ml" +# 5662 "setup.ml" module InternalConfigurePlugin = struct (* # 22 "src/plugins/internal/InternalConfigurePlugin.ml" *) @@ -6016,17 +6010,14 @@ module InternalInstallPlugin = struct let install = - let in_destdir = + let in_destdir fn = try - let destdir = - destdir () - in - (* Practically speaking destdir is prepended - * at the beginning of the target filename - *) - fun fn -> destdir^fn + (* Practically speaking destdir is prepended at the beginning of the + target filename + *) + (destdir ())^fn with PropList.Not_set _ -> - fun fn -> fn + fn in let install_file ~ctxt ?(prepend_destdir=true) ?tgt_fn src_file envdir = @@ -6471,7 +6462,7 @@ module InternalInstallPlugin = struct end -# 6474 "setup.ml" +# 6465 "setup.ml" module OCamlbuildCommon = struct (* # 22 "src/plugins/ocamlbuild/OCamlbuildCommon.ml" *) @@ -6828,11 +6819,10 @@ module OCamlbuildDocPlugin = struct run_ocamlbuild ~ctxt (index_html :: run.extra_args) argv; List.iter (fun glb -> - BaseBuilt.register - ~ctxt - BaseBuilt.BDoc - cs.cs_name - [OASISFileUtil.glob ~ctxt (Filename.concat tgt_dir glb)]) + match OASISFileUtil.glob ~ctxt (Filename.concat tgt_dir glb) with + | (_ :: _) as filenames -> + BaseBuilt.register ~ctxt BaseBuilt.BDoc cs.cs_name [filenames] + | [] -> ()) ["*.html"; "*.css"] @@ -6844,7 +6834,7 @@ module OCamlbuildDocPlugin = struct end -# 6847 "setup.ml" +# 6837 "setup.ml" module CustomPlugin = struct (* # 22 "src/plugins/custom/CustomPlugin.ml" *) @@ -6976,7 +6966,7 @@ module CustomPlugin = struct end -# 6979 "setup.ml" +# 6969 "setup.ml" open OASISTypes;; let setup_t = @@ -7037,7 +7027,7 @@ let setup_t = { oasis_version = "0.4"; ocaml_version = None; - version = "0.10"; + version = "0.11"; license = OASISLicense.DEP5License (OASISLicense.DEP5Unit @@ -8242,8 +8232,8 @@ let setup_t = plugin_data = [] }; oasis_fn = Some "_oasis"; - oasis_version = "0.4.8"; - oasis_digest = Some "o\181u\130\246\134[37Z-Cy\216\208\151"; + oasis_version = "0.4.10"; + oasis_digest = Some "\027\154\201k\198D\228+r\225\172C\214\207\155\149"; oasis_exec = None; oasis_setup_args = []; setup_update = false @@ -8251,7 +8241,7 @@ let setup_t = let setup () = BaseSetup.setup setup_t;; -# 8255 "setup.ml" +# 8245 "setup.ml" let setup_t = BaseCompat.Compat_0_4.adapt_setup_t setup_t open BaseCompat.Compat_0_4 (* OASIS_STOP *) diff --git a/src/META b/src/META index 13249a4..87021a2 100644 --- a/src/META +++ b/src/META @@ -1,6 +1,6 @@ # OASIS_START -# DO NOT EDIT (digest: 47d925b722c4289a923085abbf97bba8) -version = "0.10" +# DO NOT EDIT (digest: 0035cfa1879430f352e735e279af06d0) +version = "0.11" description = "Simple sequence (iterator) datatype and combinators" requires = "bytes" archive(byte) = "sequence.cma" @@ -9,7 +9,7 @@ archive(native) = "sequence.cmxa" archive(native, plugin) = "sequence.cmxs" exists_if = "sequence.cma" package "invert" ( - version = "0.10" + version = "0.11" description = "Simple sequence (iterator) datatype and combinators" requires = "sequence delimcc" archive(byte) = "invert.cma" @@ -20,7 +20,7 @@ package "invert" ( ) package "bigarray" ( - version = "0.10" + version = "0.11" description = "Simple sequence (iterator) datatype and combinators" requires = "sequence bigarray" archive(byte) = "bigarray.cma" diff --git a/src/Sequence.ml b/src/Sequence.ml index 3bdb9fc..aa0e350 100644 --- a/src/Sequence.ml +++ b/src/Sequence.ml @@ -150,6 +150,8 @@ let filter p seq k = seq (fun x -> if p x then k x) let append s1 s2 k = s1 k; s2 k +let append_l l k = List.iter (fun sub -> sub k) l + let concat s k = s (fun s' -> s' k) (*$R @@ -181,11 +183,32 @@ let flat_map f seq k = seq (fun x -> f x k) let flat_map_l f seq k = seq (fun x -> List.iter k (f x)) +let rec seq_list_map f l k = match l with + | [] -> k [] + | x :: tail -> + f x (fun x' -> seq_list_map f tail (fun tail' -> k (x'::tail'))) + +let seq_list l = seq_list_map (fun x->x) l + +(*$= & ~printer:Q.Print.(list @@ list int) + [[1;2];[1;3]] (seq_list [singleton 1; doubleton 2 3] |> to_list) + [] (seq_list [singleton 1; empty; doubleton 2 3] |> to_list) + [[1;2;4];[1;3;4]] (seq_list [singleton 1; doubleton 2 3; singleton 4] |> to_list) +*) + let filter_map f seq k = seq (fun x -> match f x with | None -> () - | Some y -> k y - ) + | Some y -> k y) + +let filter_mapi f seq k = + let i = ref 0 in + seq (fun x -> + let j = !i in + incr i; + match f j x with + | None -> () + | Some y -> k y) let intersperse elem seq k = let first = ref true in @@ -384,7 +407,10 @@ let group_succ_by ?(eq=fun x y -> x = y) seq k = k l; (* yield group, and start another one *) cur := [x]); (* last list *) - if !cur <> [] then k !cur + begin match !cur with + | [] -> () + | (_::_) as l -> k l + end (*$R [1;2;3;3;2;2;3;4] @@ -399,14 +425,16 @@ let group_by (type k) ?(hash=Hashtbl.hash) ?(eq=(=)) seq = let hash = hash end) in (* compute group table *) - let tbl = Tbl.create 32 in - seq - (fun x -> - let l = try Tbl.find tbl x with Not_found -> [] in - Tbl.replace tbl x (x::l) - ); + let tbl = lazy ( + let tbl = Tbl.create 32 in + seq + (fun x -> + let l = try Tbl.find tbl x with Not_found -> [] in + Tbl.replace tbl x (x::l)); + tbl + ) in fun yield -> - Tbl.iter (fun _ l -> yield l) tbl + Tbl.iter (fun _ l -> yield l) (Lazy.force tbl) (*$R [1;2;3;3;2;2;3;4] @@ -421,14 +449,16 @@ let count (type k) ?(hash=Hashtbl.hash) ?(eq=(=)) seq = let hash = hash end) in (* compute group table *) - let tbl = Tbl.create 32 in - seq - (fun x -> - let n = try Tbl.find tbl x with Not_found -> 0 in - Tbl.replace tbl x (n+1) - ); + let tbl = lazy ( + let tbl = Tbl.create 32 in + seq + (fun x -> + let n = try Tbl.find tbl x with Not_found -> 0 in + Tbl.replace tbl x (n+1)); + tbl + ) in fun yield -> - Tbl.iter (fun x n -> yield (x,n)) tbl + Tbl.iter (fun x n -> yield (x,n)) (Lazy.force tbl) (*$R [1;2;3;3;2;2;3;4] @@ -714,6 +744,32 @@ let min_exn ?lt seq = match min ?lt seq with 0 (0 -- 100 |> min_exn ?lt:None) *) +let sum seq = + let n = ref 0 in + seq (fun x -> n := !n + x); + !n + +(*$T + (of_list [1;2;3] |> sum) = 6 +*) + +(* https://en.wikipedia.org/wiki/Kahan_summation_algorithm *) +let sumf seq : float = + let sum = ref 0. in + let c = ref 0. in (* error compensation *) + seq + (fun x -> + let y = x -. !c in + let t = !sum +. y in + c := (t -. !sum) -. y; + sum := t); + !sum + +(*$R + let seq = of_list [10000.0; 3.14159; 2.71828] in + assert_equal ~printer:string_of_float 10005.85987 (sumf seq) +*) + exception ExitHead let head seq = @@ -932,6 +988,10 @@ let of_list l k = List.iter k l let on_list f l = to_list (f (of_list l)) +let pair_with_idx seq k = + let r = ref 0 in + seq (fun x -> let n = !r in incr r; k (n,x)) + let to_opt = head let of_opt o k = match o with @@ -1047,7 +1107,7 @@ let to_buffer seq buf = (*$R let b = Buffer.create 4 in "hello world" - |> of_str |> rev |> map Char.uppercase + |> of_str |> rev |> map Char.uppercase_ascii |> (fun seq -> to_buffer seq b); OUnit.assert_equal "DLROW OLLEH" (Buffer.contents b); *) diff --git a/src/Sequence.mli b/src/Sequence.mli index a510c99..384b987 100644 --- a/src/Sequence.mli +++ b/src/Sequence.mli @@ -184,6 +184,11 @@ val append : 'a t -> 'a t -> 'a t (** Append two sequences. Iterating on the result is like iterating on the first, then on the second. *) +val append_l : 'a t list -> 'a t +(** Append sequences. Iterating on the result is like iterating + on the each sequence of the list in order. + @since 0.11 *) + val concat : 'a t t -> 'a t (** Concatenate a sequence of sequences into one sequence. *) @@ -200,11 +205,25 @@ val flat_map_l : ('a -> 'b list) -> 'a t -> 'b t (** Convenience function combining {!flat_map} and {!of_list} @since 0.8 *) +val seq_list : 'a t list -> 'a list t +(** [seq_list l] returns all the ways to pick one element in each sub-sequence + in [l]. Assumes the sub-sequences can be iterated on several times. + @since 0.11 *) + +val seq_list_map : ('a -> 'b t) -> 'a list -> 'b list t +(** [seq_list_map f l] maps [f] over every element of [l], + then calls {!seq_list} + @since 0.11 *) + val filter_map : ('a -> 'b option) -> 'a t -> 'b t (** Map and only keep non-[None] elements Formerly [fmap] @since 0.5 *) +val filter_mapi : (int -> 'a -> 'b option) -> 'a t -> 'b t +(** Map with indices, and only keep non-[None] elements + @since 0.11 *) + val intersperse : 'a -> 'a t -> 'a t (** Insert the single element between every element of the sequence *) @@ -242,7 +261,7 @@ val sorted : ?cmp:('a -> 'a -> int) -> 'a t -> bool @since 0.9 *) val group_succ_by : ?eq:('a -> 'a -> bool) -> 'a t -> 'a list t -(** Group equal consecutive elements. +(** Group equal consecutive elements. Linear time. Formerly synonym to [group]. @since 0.6 *) @@ -250,12 +269,14 @@ val group_by : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) -> 'a t -> 'a list t (** Group equal elements, disregarding their order of appearance. The result sequence is traversable as many times as required. + precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold. @since 0.6 *) val count : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) -> 'a t -> ('a * int) t (** Map each distinct element to its number of occurrences in the whole seq. Similar to [group_by seq |> map (fun l->List.hd l, List.length l)] + precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold. @since 0.10 *) val uniq : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t @@ -300,6 +321,7 @@ val join_by : ?eq:'key equal -> ?hash:'key hash -> values [(x,y)] from [(a,b)] with the same [key] using [merge]. If [merge] returns [None], the combination of values is discarded. + precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold. @since 0.10 *) val join_all_by : ?eq:'key equal -> ?hash:'key hash -> @@ -329,6 +351,7 @@ val group_join_by : ?eq:'a equal -> ?hash:'a hash -> sequence such that [eq x (key y)]. Elements of the first sequences without corresponding values in the second one are mapped to [[]] + precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold. @since 0.10 *) val inter : @@ -336,6 +359,7 @@ val inter : 'a t -> 'a t -> 'a t (** Intersection of two collections. Each element will occur at most once in the result. Eager. + precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold. @since 0.10 *) (*$= @@ -348,6 +372,7 @@ val union : 'a t -> 'a t -> 'a t (** Union of two collections. Each element will occur at most once in the result. Eager. + precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold. @since 0.10 *) (*$= @@ -368,6 +393,7 @@ val subset : ?eq:'a equal -> ?hash:'a hash -> 'a t -> 'a t -> bool (** [subset a b] returns [true] if all elements of [a] belong to [b]. Eager. + precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold. @since 0.10 *) (*$T @@ -402,6 +428,14 @@ val min_exn : ?lt:('a -> 'a -> bool) -> 'a t -> 'a @raise Not_found if the sequence is empty @since 0.10 *) +val sum : int t -> int +(** Sum of elements + @since 0.11 *) + +val sumf : float t -> float +(** Sum of elements, using Kahan summation + @since 0.11 *) + val head : 'a t -> 'a option (** First element, if any, otherwise [None] @since 0.5.1 *) @@ -477,6 +511,10 @@ val on_list : ('a t -> 'b t) -> 'a list -> 'b list @since 0.5.2 *) +val pair_with_idx : 'a t -> (int * 'a) t +(** Similar to {!zip_i} but returns a normal sequence of tuples + @since 0.11 *) + val to_opt : 'a t -> 'a option (** Alias to {!head} @since 0.5.1 *) diff --git a/src/SequenceLabels.ml b/src/SequenceLabels.ml new file mode 100644 index 0000000..fb15e92 --- /dev/null +++ b/src/SequenceLabels.ml @@ -0,0 +1 @@ +include Sequence diff --git a/src/sequenceLabels.mli b/src/SequenceLabels.mli similarity index 79% rename from src/sequenceLabels.mli rename to src/SequenceLabels.mli index b28e492..5b582e2 100644 --- a/src/sequenceLabels.mli +++ b/src/SequenceLabels.mli @@ -17,6 +17,9 @@ type +'a sequence = 'a t type (+'a, +'b) t2 = ('a -> 'b -> unit) -> unit (** Sequence of pairs of values of type ['a] and ['b]. *) +type 'a equal = 'a -> 'a -> bool +type 'a hash = 'a -> int + (** {2 Build a sequence} *) val from_iter : (('a -> unit) -> unit) -> 'a t @@ -115,15 +118,25 @@ val exists : f:('a -> bool) -> 'a t -> bool val mem : ?eq:('a -> 'a -> bool) -> x:'a -> 'a t -> bool (** Is the value a member of the sequence? - @param eq the equality predicate to use (default [(=)]) *) + @param eq the equality predicate to use (default [(=)]) + @since 0.5 *) -val find : f:('a -> 'b option) -> 'a t -> 'b option -(** Find the first element on which the function doesn't return [None] *) +val find : ('a -> 'b option) -> 'a t -> 'b option +(** Find the first element on which the function doesn't return [None] + @since 0.5 *) + +val find_map : f:('a -> 'b option) -> 'a t -> 'b option +(** Alias to {!find} + @since 0.10 *) val findi : f:(int -> 'a -> 'b option) -> 'a t -> 'b option (** Indexed version of {!find} @since 0.9 *) +val find_mapi : f:(int -> 'a -> 'b option) -> 'a t -> 'b option +(** Alias to {!findi} + @since 0.10 *) + val find_pred : f:('a -> bool) -> 'a t -> 'a option (** [find_pred p l] finds the first element of [l] that satisfies [p], or returns [None] if no element satisfies [p] @@ -149,6 +162,11 @@ val append : 'a t -> 'a t -> 'a t (** Append two sequences. Iterating on the result is like iterating on the first, then on the second. *) +val append_l : 'a t list -> 'a t +(** Append sequences. Iterating on the result is like iterating + on the each sequence of the list in order. + @since 0.11 *) + val concat : 'a t t -> 'a t (** Concatenate a sequence of sequences into one sequence. *) @@ -165,6 +183,20 @@ val flat_map_l : f:('a -> 'b list) -> 'a t -> 'b t val filter_map : f:('a -> 'b option) -> 'a t -> 'b t (** Alias to {!fmap} with a more explicit name *) +val filter_mapi : f:(int -> 'a -> 'b option) -> 'a t -> 'b t +(** Map with indices, and only keep non-[None] elements + @since 0.11 *) + +val seq_list : 'a t list -> 'a list t +(** [seq_list l] returns all the ways to pick one element in each sub-sequence + in [l]. Assumes the sub-sequences can be iterated on several times. + @since 0.11 *) + +val seq_list_map : f:('a -> 'b t) -> 'a list -> 'b list t +(** [seq_list_map f l] maps [f] over every element of [l], + then calls {!seq_list} + @since 0.11 *) + val intersperse : x:'a -> 'a t -> 'a t (** Insert the single element between every element of the sequence *) @@ -210,6 +242,7 @@ val group_by : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) -> 'a t -> 'a list t (** Group equal elements, disregarding their order of appearance. The result sequence is traversable as many times as required. + precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold. @since 0.6 *) val count : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) -> @@ -239,7 +272,8 @@ val diagonal : 'a t -> ('a * 'a) t @since 0.9 *) val product2 : 'a t -> 'b t -> ('a, 'b) t2 -(** Binary version of {!product}. Same requirements. *) +(** Binary version of {!product}. Same requirements. + @since 0.5 *) 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 @@ -247,6 +281,98 @@ 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 join_by : ?eq:'key equal -> ?hash:'key hash -> + ('a -> 'key) -> ('b -> 'key) -> + merge:('key -> 'a -> 'b -> 'c option) -> + 'a t -> + 'b t -> + 'c t +(** [join key1 key2 ~merge] is a binary operation + that takes two sequences [a] and [b], projects their + elements resp. with [key1] and [key2], and combine + values [(x,y)] from [(a,b)] with the same [key] + using [merge]. If [merge] returns [None], the combination + of values is discarded. + precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold. + @since 0.10 *) + +val join_all_by : ?eq:'key equal -> ?hash:'key hash -> + ('a -> 'key) -> ('b -> 'key) -> + merge:('key -> 'a list -> 'b list -> 'c option) -> + 'a t -> + 'b t -> + 'c t +(** [join_all_by key1 key2 ~merge] is a binary operation + that takes two sequences [a] and [b], projects their + elements resp. with [key1] and [key2], and, for each key [k] + occurring in at least one of them: + - compute the list [l1] of elements of [a] that map to [k] + - compute the list [l2] of elements of [b] that map to [k] + - call [merge k l1 l2]. If [merge] returns [None], the combination + of values is discarded, otherwise it returns [Some c] + and [c] is inserted in the result. + @since 0.10 *) + +val group_join_by : ?eq:'a equal -> ?hash:'a hash -> + ('b -> 'a) -> + 'a t -> + 'b t -> + ('a * 'b list) t +(** [group_join_by key2] associates to every element [x] of + the first sequence, all the elements [y] of the second + sequence such that [eq x (key y)]. Elements of the first + sequences without corresponding values in the second one + are mapped to [[]] + precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold. + @since 0.10 *) + +val inter : + ?eq:'a equal -> ?hash:'a hash -> + 'a t -> 'a t -> 'a t +(** Intersection of two collections. Each element will occur at most once + in the result. Eager. + precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold. + @since 0.10 *) + +(*$= + [2;4;5;6] (inter (1--6) (cons 2 (4--10)) |> sort |> to_list) + [] (inter (0--5) (6--10) |> to_list) +*) + +val union : + ?eq:'a equal -> ?hash:'a hash -> + 'a t -> 'a t -> 'a t +(** Union of two collections. Each element will occur at most once + in the result. Eager. + precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold. + @since 0.10 *) + +(*$= + [2;4;5;6] (union (4--6) (cons 2 (4--5)) |> sort |> to_list) +*) + +val diff : + ?eq:'a equal -> ?hash:'a hash -> + 'a t -> 'a t -> 'a t +(** Set difference. Eager. + @since 0.10 *) + +(*$= + [1;2;8;9;10] (diff (1--10) (3--7) |> to_list) +*) + +val subset : + ?eq:'a equal -> ?hash:'a hash -> + 'a t -> 'a t -> bool +(** [subset a b] returns [true] if all elements of [a] belong to [b]. Eager. + precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold. + @since 0.10 *) + +(*$T + subset (2 -- 4) (1 -- 4) + not (subset (1 -- 4) (2 -- 10)) +*) + 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 @@ -260,16 +386,36 @@ val max : ?lt:('a -> 'a -> bool) -> 'a t -> 'a option @return None if the sequence is empty, Some [m] where [m] is the maximal element otherwise *) +val max_exn : ?lt:('a -> 'a -> bool) -> 'a t -> 'a +(** Unsafe version of {!max} + @raise Not_found if the sequence is empty + @since 0.10 *) + 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 min_exn : ?lt:('a -> 'a -> bool) -> 'a t -> 'a +(** Unsafe version of {!min} + @raise Not_found if the sequence is empty + @since 0.10 *) + +val sum : int t -> int +(** Sum of elements + @since 0.11 *) + +val sumf : float t -> float +(** Sum of elements, using Kahan summation + @since 0.11 *) + val head : 'a t -> 'a option -(** First element, if any, otherwise [None] *) +(** First element, if any, otherwise [None] + @since 0.5.1 *) val head_exn : 'a t -> 'a (** First element, if any, fails - @raise Invalid_argument if the sequence is empty *) + @raise Invalid_argument if the sequence is empty + @since 0.5.1 *) val take : int -> 'a t -> 'a t (** Take at most [n] elements from the sequence. Works on infinite @@ -282,7 +428,8 @@ val take_while : f:('a -> bool) -> 'a t -> 'a t val fold_while : f:('a -> 'b -> 'a * [`Stop | `Continue]) -> init:'a -> 'b t -> 'a (** Folds over elements of the sequence, stopping early if the accumulator - returns [('a, `Stop)] *) + returns [('a, `Stop)] + @since 0.5.5 *) val drop : int -> 'a t -> 'a t (** Drop the [n] first elements of the sequence. Lazy. *) @@ -332,10 +479,17 @@ val to_rev_list : 'a t -> 'a list val of_list : 'a list -> 'a t val on_list : ('a t -> 'b t) -> 'a list -> 'b list -(** [on_list f l] is equivalent to [to_list @@ f @@ of_list l]. *) +(** [on_list f l] is equivalent to [to_list @@ f @@ of_list l]. + @since 0.5.2 +*) + +val pair_with_idx : 'a t -> (int * 'a) t +(** Similar to {!zip_i} but returns a normal sequence of tuples + @since 0.11 *) val to_opt : 'a t -> 'a option -(** Alias to {!head} *) +(** Alias to {!head} + @since 0.5.1 *) val to_array : 'a t -> 'a array (** Convert to an array. Currently not very efficient because @@ -353,7 +507,8 @@ val array_slice : 'a array -> int -> int -> 'a t from [i] to [j] *) val of_opt : 'a option -> 'a t -(** Iterate on 0 or 1 values. *) +(** Iterate on 0 or 1 values. + @since 0.5.1 *) val of_stream : 'a Stream.t -> 'a t (** Sequence of elements of a stream (usable only once) *) @@ -401,7 +556,8 @@ val to_str : char t -> string val concat_str : string t -> string (** Concatenate strings together, eagerly. - Also see {!intersperse} to add a separator. *) + Also see {!intersperse} to add a separator. + @since 0.5 *) exception OneShotSequence (** Raised when the user tries to iterate several times on @@ -547,16 +703,20 @@ module Infix : sig It will therefore be empty if [a < b]. *) val (>>=) : 'a t -> ('a -> 'b t) -> 'b t - (** Monadic bind (infix version of {!flat_map} *) + (** Monadic bind (infix version of {!flat_map} + @since 0.5 *) val (>|=) : 'a t -> ('a -> 'b) -> 'b t - (** Infix version of {!map} *) + (** Infix version of {!map} + @since 0.5 *) val (<*>) : ('a -> 'b) t -> 'a t -> 'b t - (** Applicative operator (product+application) *) + (** Applicative operator (product+application) + @since 0.5 *) val (<+>) : 'a t -> 'a t -> 'a t - (** Concatenation of sequences *) + (** Concatenation of sequences + @since 0.5 *) end include module type of Infix @@ -600,7 +760,7 @@ val to_string : ?sep:string -> ('a -> string) -> 'a t -> string Sequence.IO.lines "a" |> Sequence.to_list ]} -*) + @since 0.5.1 *) module IO : sig val lines_of : ?mode:int -> ?flags:open_flag list -> @@ -630,7 +790,7 @@ module IO : sig val write_bytes_to : ?mode:int -> ?flags:open_flag list -> string -> Bytes.t t -> unit - (** *) + (** @since 0.5.4 *) val write_lines : ?mode:int -> ?flags:open_flag list -> string -> string t -> unit @@ -638,4 +798,5 @@ module IO : sig val write_bytes_lines : ?mode:int -> ?flags:open_flag list -> string -> Bytes.t t -> unit + (** @since 0.5.4 *) end diff --git a/src/bigarray/sequenceBigarray.ml b/src/bigarray/SequenceBigarray.ml similarity index 100% rename from src/bigarray/sequenceBigarray.ml rename to src/bigarray/SequenceBigarray.ml diff --git a/src/bigarray/sequenceBigarray.mli b/src/bigarray/SequenceBigarray.mli similarity index 100% rename from src/bigarray/sequenceBigarray.mli rename to src/bigarray/SequenceBigarray.mli diff --git a/src/invert/sequenceInvert.ml b/src/invert/SequenceInvert.ml similarity index 100% rename from src/invert/sequenceInvert.ml rename to src/invert/SequenceInvert.ml diff --git a/src/invert/sequenceInvert.mli b/src/invert/SequenceInvert.mli similarity index 100% rename from src/invert/sequenceInvert.mli rename to src/invert/SequenceInvert.mli diff --git a/src/sequenceLabels.ml b/src/sequenceLabels.ml deleted file mode 120000 index b990b32..0000000 --- a/src/sequenceLabels.ml +++ /dev/null @@ -1 +0,0 @@ -Sequence.ml \ No newline at end of file