From 4748655708de373c610d3f8c113690f0dbbcf808 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 26 Dec 2016 00:45:03 +0100 Subject: [PATCH] =?UTF-8?q?add=20`init,fold=5Fmap,fold=5Ffilter=5Fmap,sort?= =?UTF-8?q?ed,diagonal,findi,=E2=80=A6`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sequence.ml | 79 ++++++++++++++++++++++++++++++++++++++++++ src/sequence.mli | 38 ++++++++++++++++++++ src/sequenceLabels.mli | 42 ++++++++++++++++++++++ 3 files changed, 159 insertions(+) diff --git a/src/sequence.ml b/src/sequence.ml index b5ce58d..1e38e3b 100644 --- a/src/sequence.ml +++ b/src/sequence.ml @@ -48,6 +48,17 @@ let repeat x k = while true do k x done (seq |> take 3 |> to_list); *) +let init f yield = + let rec aux i = + yield (f i); + aux (i+1) + in + aux 0 + +(*$= + [0;1;2;3;4] (init (fun x->x) |> take 5 |> to_list) +*) + let rec iterate f x k = k x; iterate f (f x) k @@ -94,6 +105,28 @@ let foldi f init seq = OUnit.assert_equal [1, "world"; 0, "hello"] l; *) +let fold_map f init seq yield = + let r = ref init in + seq + (fun x -> + let acc', y = f !r x in + r := acc'; + yield y) + +(*$= & ~printer:Q.Print.(list int) + [0;1;3;5] (0--3 |> fold_map (fun prev x -> x,prev+x) 0 |> to_list) +*) + +let fold_filter_map f init seq yield = + let r = ref init in + seq + (fun x -> + let acc', y = f !r x in + r := acc'; + match y with + | None -> () + | Some y' -> yield y') + let map f seq k = seq (fun x -> k (f x)) let mapi f seq k = @@ -320,6 +353,23 @@ let sort ?(cmp=Pervasives.compare) seq = |> OUnit.assert_equal [100;99;98;97] *) +exception Exit_sorted + +let sorted ?(cmp=Pervasives.compare) seq = + let prev = ref None in + try + seq (fun x -> match !prev with + | Some y when cmp y x > 0 -> raise Exit_sorted + | _ -> prev := Some x); + true + with Exit_sorted -> false + +(*$T + of_list [1;2;3;4] |> sorted + not (of_list [1;2;3;0;4] |> sorted) + sorted empty +*) + let group_succ_by ?(eq=fun x y -> x = y) seq k = let cur = ref [] in seq (fun x -> @@ -413,6 +463,16 @@ let product outer inner k = let product2 outer inner k = outer (fun x -> inner (fun y -> k x y)) +let rec diagonal l yield = match l with + | [] -> () + | x::tail -> + List.iter (fun y -> yield (x,y)) tail; + diagonal tail yield + +(*$= + [0,1; 0,2; 1,2] (diagonal [0;1;2] |> to_list) + *) + let join ~join_row s1 s2 k = s1 (fun a -> s2 (fun b -> @@ -607,6 +667,25 @@ let find f seq = end; !r +let findi f seq = + let i = ref 0 in + let r = ref None in + begin + try + seq + (fun x -> match f !i x with + | None -> incr i + | Some _ as res -> r := res; raise ExitFind); + with ExitFind -> () + end; + !r + +let find_pred f seq = find (fun x -> if f x then Some x else None) seq + +let find_pred_exn f seq = match find_pred f seq with + | Some x -> x + | None -> raise Not_found + let length seq = let r = ref 0 in seq (fun _ -> incr r); diff --git a/src/sequence.mli b/src/sequence.mli index 379a158..bfc8ac1 100644 --- a/src/sequence.mli +++ b/src/sequence.mli @@ -57,6 +57,10 @@ val singleton : 'a -> 'a t val doubleton : 'a -> 'a -> 'a t (** Sequence with exactly two elements *) +val init : (int -> 'a) -> 'a t +(** [init f] is the infinite sequence [f 0; f 1; f 2; …]. + @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] *) @@ -103,6 +107,17 @@ val fold : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a val foldi : ('a -> int -> 'b -> 'a) -> 'a -> 'b t -> 'a (** Fold over elements of the sequence and their index, consuming it *) +val fold_map : ('acc -> 'a -> 'acc * 'b) -> 'acc -> 'a t -> 'b t +(** [fold_map f acc l] is like {!map}, but it carries some state as in + {!fold}. The state is not returned, it is just used to thread some + information to the map function. + @since NEXT_RELEASE *) + +val fold_filter_map : ('acc -> 'a -> 'acc * 'b option) -> 'acc -> 'a t -> 'b t +(** [fold_filter_map f acc l] is a {!fold_map}-like function, but the + function can choose to skip an element by retuning [None]. + @since NEXT_RELEASE *) + val map : ('a -> 'b) -> 'a t -> 'b t (** Map objects of the sequence into other elements, lazily *) @@ -129,6 +144,20 @@ 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 findi : (int -> 'a -> 'b option) -> 'a t -> 'b option +(** Indexed version of {!find} + @since NEXT_RELEASE *) + +val find_pred : ('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] + @since NEXT_RELEASE *) + +val find_pred_exn : ('a -> bool) -> 'a t -> 'a +(** Unsafe version of {!find_pred} + @raise Not_found if no such element is found + @since NEXT_RELEASE *) + val length : 'a t -> int (** How long is the sequence? Forces the sequence. *) @@ -197,6 +226,10 @@ val sort : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t val sort_uniq : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t (** Sort the sequence and remove duplicates. Eager, same as [sort] *) +val sorted : ?cmp:('a -> 'a -> int) -> 'a t -> bool +(** Checks whether the sequence is sorted. Eager, same as {!sort}. + @since NEXT_RELEASE *) + val group_succ_by : ?eq:('a -> 'a -> bool) -> 'a t -> 'a list t (** Group equal consecutive elements. Formerly synonym to [group]. @@ -218,6 +251,11 @@ val product : 'a t -> 'b t -> ('a * 'b) t as required (several times), possibly by calling {!persistent} on it beforehand. *) +val diagonal : 'a list -> ('a * 'a) t +(** All pairs of distinct positions of the list. [diagonal l] will + return the list of [List.nth i l, List.nth j l] if [i < j]. + @since NEXT_RELEASE *) + val product2 : 'a t -> 'b t -> ('a, 'b) t2 (** Binary version of {!product}. Same requirements. @since 0.5 *) diff --git a/src/sequenceLabels.mli b/src/sequenceLabels.mli index 1a092eb..6ef97f3 100644 --- a/src/sequenceLabels.mli +++ b/src/sequenceLabels.mli @@ -35,6 +35,10 @@ val singleton : 'a -> 'a t val doubleton : 'a -> 'a -> 'a t (** Sequence with exactly two elements *) +val init : f:(int -> 'a) -> 'a t +(** [init f] is the infinite sequence [f 0; f 1; f 2; …]. + @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] *) @@ -81,6 +85,17 @@ val fold : f:('a -> 'b -> 'a) -> init:'a -> 'b t -> 'a val foldi : f:('a -> int -> 'b -> 'a) -> init:'a -> 'b t -> 'a (** Fold over elements of the sequence and their index, consuming it *) +val fold_map : f:('acc -> 'a -> 'acc * 'b) -> init:'acc -> 'a t -> 'b t +(** [fold_map f acc l] is like {!map}, but it carries some state as in + {!fold}. The state is not returned, it is just used to thread some + information to the map function. + @since NEXT_RELEASE *) + +val fold_filter_map : f:('acc -> 'a -> 'acc * 'b option) -> init:'acc -> 'a t -> 'b t +(** [fold_filter_map f acc l] is a {!fold_map}-like function, but the + function can choose to skip an element by retuning [None]. + @since NEXT_RELEASE *) + val map : f:('a -> 'b) -> 'a t -> 'b t (** Map objects of the sequence into other elements, lazily *) @@ -105,6 +120,20 @@ val mem : ?eq:('a -> 'a -> bool) -> x:'a -> 'a t -> bool val find : f:('a -> 'b option) -> 'a t -> 'b option (** Find the first element on which the function doesn't return [None] *) +val findi : f:(int -> 'a -> 'b option) -> 'a t -> 'b option +(** Indexed version of {!find} + @since NEXT_RELEASE *) + +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] + @since NEXT_RELEASE *) + +val find_pred_exn : f:('a -> bool) -> 'a t -> 'a +(** Unsafe version of {!find_pred} + @raise Not_found if no such element is found + @since NEXT_RELEASE *) + val length : 'a t -> int (** How long is the sequence? Forces the sequence. *) @@ -168,6 +197,10 @@ val sort : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t val sort_uniq : ?cmp:('a -> 'a -> int) -> 'a t -> 'a t (** Sort the sequence and remove duplicates. Eager, same as [sort] *) +val sorted : ?cmp:('a -> 'a -> int) -> 'a t -> bool +(** Checks whether the sequence is sorted. Eager, same as {!sort}. + @since NEXT_RELEASE *) + val group_succ_by : ?eq:('a -> 'a -> bool) -> 'a t -> 'a list t (** Group equal consecutive elements. Formerly synonym to [group]. @@ -189,6 +222,11 @@ val product : 'a t -> 'b t -> ('a * 'b) t as required (several times), possibly by calling {!persistent} on it beforehand. *) +val diagonal : 'a list -> ('a * 'a) t +(** All pairs of distinct positions of the list. [diagonal l] will + return the list of [List.nth i l, List.nth j l] if [i < j]. + @since NEXT_RELEASE *) + val product2 : 'a t -> 'b t -> ('a, 'b) t2 (** Binary version of {!product}. Same requirements. *) @@ -382,6 +420,10 @@ val int_range_by : step:int -> start:int -> stop:int -> int t @since NEXT_RELEASE @raise Invalid_argument if [step=0] *) +val bools : bool t +(** Iterates on [true] and [false] + @since NEXT_RELEASE *) + val of_set : (module Set.S with type elt = 'a and type t = 'b) -> 'b -> 'a t (** Convert the given set to a sequence. The set module must be provided. *)