diff --git a/Makefile b/Makefile index a6946d2c..ce07e4f6 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,7 @@ push_doc_gh: doc cp -r containers.docdir/* dev/ && \ git add --all dev -DONTTEST=myocamlbuild.ml setup.ml $(wildcard src/**/*.cppo.*) +DONTTEST=myocamlbuild.ml setup.ml $(wildcard src/**/*.cppo.*) $(wildcard src/**/*Labels*) QTESTABLE=$(filter-out $(DONTTEST), \ $(wildcard src/core/*.ml) \ $(wildcard src/core/*.mli) \ diff --git a/_oasis b/_oasis index 879bb22b..04c64ad5 100644 --- a/_oasis +++ b/_oasis @@ -35,6 +35,7 @@ Library "containers" CCFun, CCHash, CCInt, CCBool, CCFloat, CCArray, CCRef, CCSet, CCOrd, CCRandom, CCString, CCHashtbl, CCMap, CCFormat, CCIO, CCInt64, CCChar, CCResult, CCParse, CCArray_slice, + CCListLabels, CCArrayLabels, Containers BuildDepends: bytes, result # BuildDepends: bytes, bisect_ppx diff --git a/_tags b/_tags index 0d8627c3..e0f0e2f1 100644 --- a/_tags +++ b/_tags @@ -159,3 +159,4 @@ true: annot, bin_annot or or : inline(15) and not : warn_A, warn(-4), warn(-44) true: no_alias_deps, safe_string, short_paths +: nolabels diff --git a/src/core/CCArray.ml b/src/core/CCArray.ml index 98460fba..728dbb36 100644 --- a/src/core/CCArray.ml +++ b/src/core/CCArray.ml @@ -22,9 +22,9 @@ type 'a t = 'a array let empty = [| |] -let map ~f a = Array.map f a +let map = Array.map -let map2 ~f a b = +let map2 f a b = if Array.length a <> Array.length b then invalid_arg "map2"; Array.init (Array.length a) (fun i -> f (Array.unsafe_get a i) (Array.unsafe_get b i)) @@ -49,15 +49,15 @@ let get_safe a i = let set = Array.set -let fold ~f ~init a = Array.fold_left f init a +let fold = Array.fold_left -let foldi ~f ~init a = +let foldi f acc a = let rec aux acc i = if i = Array.length a then acc else aux (f acc i a.(i)) (i+1) in - aux init 0 + aux acc 0 -let fold_while ~f ~init a = +let fold_while f acc a = let rec fold_while_i f acc i = if i < Array.length a then let acc, cont = f acc a.(i) in @@ -65,16 +65,15 @@ let fold_while ~f ~init a = | `Stop -> acc | `Continue -> fold_while_i f acc (i+1) else acc - in fold_while_i f init 0 + in fold_while_i f acc 0 (*$T - fold_while ~f:(fun acc b -> if b then acc+1, `Continue else acc, `Stop) \ - ~init:0 (Array.of_list [true;true;false;true]) = 2 + fold_while (fun acc b -> if b then acc+1, `Continue else acc, `Stop) 0 (Array.of_list [true;true;false;true]) = 2 *) -let iter ~f a = Array.iter f a +let iter = Array.iter -let iteri ~f a = Array.iteri f a +let iteri = Array.iteri let blit = Array.blit @@ -99,53 +98,53 @@ let reverse_in_place a = a = [| 6;5;4;3;2;1 |] *) -let sorted ~f a = +let sorted cmp a = let b = Array.copy a in - Array.sort f b; + Array.sort cmp b; b (*$= & ~cmp:(=) ~printer:Q.Print.(array int) - [||] (sorted ~f:Pervasives.compare [||]) - [|0;1;2;3;4|] (sorted ~f:Pervasives.compare [|3;2;1;4;0|]) + [||] (sorted Pervasives.compare [||]) + [|0;1;2;3;4|] (sorted Pervasives.compare [|3;2;1;4;0|]) *) (*$Q Q.(array int) (fun a -> \ let b = Array.copy a in \ - Array.sort Pervasives.compare b; b = sorted ~f:Pervasives.compare a) + Array.sort Pervasives.compare b; b = sorted Pervasives.compare a) *) -let sort_indices ~f:cmp a = +let sort_indices cmp a = let len = Array.length a in let b = Array.init len (fun k->k) in Array.sort (fun k1 k2 -> cmp a.(k1) a.(k2)) b; b (*$= & ~cmp:(=) ~printer:Q.Print.(array int) - [||] (sort_indices ~f:Pervasives.compare [||]) - [|4;2;1;0;3|] (sort_indices ~f:Pervasives.compare [|"d";"c";"b";"e";"a"|]) + [||] (sort_indices Pervasives.compare [||]) + [|4;2;1;0;3|] (sort_indices Pervasives.compare [|"d";"c";"b";"e";"a"|]) *) (*$Q Q.(array printable_string) (fun a -> \ - let b = sort_indices ~f:String.compare a in \ - sorted ~f:String.compare a = map ~f:(Array.get a) b) + let b = sort_indices String.compare a in \ + sorted String.compare a = Array.map (Array.get a) b) *) -let sort_ranking ~f:cmp a = +let sort_ranking cmp a = let cmp_int : int -> int -> int = Pervasives.compare in - sort_indices ~f:cmp_int (sort_indices ~f:cmp a) + sort_indices cmp_int (sort_indices cmp a) (*$= & ~cmp:(=) ~printer:Q.Print.(array int) - [||] (sort_ranking ~f:Pervasives.compare [||]) - [|3;2;1;4;0|] (sort_ranking ~f:Pervasives.compare [|"d";"c";"b";"e";"a"|]) + [||] (sort_ranking Pervasives.compare [||]) + [|3;2;1;4;0|] (sort_ranking Pervasives.compare [|"d";"c";"b";"e";"a"|]) *) (*$Q Q.(array printable_string) (fun a -> \ - let b = sort_ranking ~f:String.compare a in \ - let a_sorted = sorted ~f:String.compare a in \ - a = map ~f:(Array.get a_sorted) b) + let b = sort_ranking String.compare a in \ + let a_sorted = sorted String.compare a in \ + a = Array.map (Array.get a_sorted) b) *) let rev a = @@ -169,16 +168,16 @@ let rec find_aux f a i = | Some _ as res -> res | None -> find_aux f a (i+1) -let find ~f a = +let find f a = find_aux (fun _ -> f ) a 0 -let findi ~f a = +let findi f a = find_aux f a 0 -let find_idx ~f a = - find_aux (fun i x -> if f x then Some (i,x) else None) a 0 +let find_idx p a = + find_aux (fun i x -> if p x then Some (i,x) else None) a 0 -let filter_map ~f a = +let filter_map f a = let rec aux acc i = if i = Array.length a then ( @@ -198,8 +197,8 @@ let filter_map ~f a = = [| "2"; "4"; "6" |] *) -let filter ~f a = - filter_map a ~f:(fun x -> if f x then Some x else None) +let filter p a = + filter_map (fun x -> if p x then Some x else None) a (* append [rev a] in front of [acc] *) let rec __rev_append_list a acc i = @@ -208,7 +207,7 @@ let rec __rev_append_list a acc i = else __rev_append_list a (a.(i) :: acc) (i+1) -let flat_map ~f a = +let flat_map f a = let rec aux acc i = if i = Array.length a then ( @@ -252,11 +251,11 @@ let _lookup_exn ~cmp k a i j = | n when n<0 -> _lookup_rec ~cmp k a (i+1) (j-1) | _ -> raise Not_found (* too high *) -let lookup_exn ?(cmp=Pervasives.compare) ~key a = - _lookup_exn ~cmp key a 0 (Array.length a-1) +let lookup_exn ?(cmp=Pervasives.compare) k a = + _lookup_exn ~cmp k a 0 (Array.length a-1) -let lookup ?(cmp=Pervasives.compare) ~key a = - try Some (_lookup_exn ~cmp key a 0 (Array.length a-1)) +let lookup ?(cmp=Pervasives.compare) k a = + try Some (_lookup_exn ~cmp k a 0 (Array.length a-1)) with Not_found -> None (*$T @@ -269,20 +268,20 @@ let lookup ?(cmp=Pervasives.compare) ~key a = lookup 2 [| 1 |] = None *) -let bsearch ?(cmp=Pervasives.compare) ~key a = +let bsearch ?(cmp=Pervasives.compare) k a = let rec aux i j = if i > j then `Just_after j else let middle = i + (j - i) / 2 in (* avoid overflow *) - match cmp key a.(middle) with + match cmp k a.(middle) with | 0 -> `At middle | n when n<0 -> aux i (middle - 1) | _ -> aux (middle + 1) j in let n = Array.length a in if n=0 then `Empty - else match cmp a.(0) key, cmp a.(n-1) key with + else match cmp a.(0) k, cmp a.(n-1) k with | c, _ when c>0 -> `All_bigger | _, c when c<0 -> `All_lower | _ -> aux 0 (n-1) @@ -297,37 +296,37 @@ let bsearch ?(cmp=Pervasives.compare) ~key a = bsearch 3 [| |] = `Empty *) -let (>>=) a f = flat_map ~f a +let (>>=) a f = flat_map f a -let (>>|) a f = map ~f a +let (>>|) a f = map f a -let (>|=) a f = map ~f a +let (>|=) a f = map f a -let for_all ~f a = +let for_all p a = let rec aux i = - i = Array.length a || (f a.(i) && aux (i+1)) + i = Array.length a || (p a.(i) && aux (i+1)) in aux 0 -let exists ~f a = +let exists p a = let rec aux i = - i <> Array.length a && (f a.(i) || aux (i+1)) + i <> Array.length a && (p a.(i) || aux (i+1)) in aux 0 let rec _for_all2 p a1 a2 i1 i2 ~len = len=0 || (p a1.(i1) a2.(i2) && _for_all2 p a1 a2 (i1+1) (i2+1) ~len:(len-1)) -let for_all2 ~f a b = +let for_all2 p a b = Array.length a = Array.length b && - _for_all2 f a b 0 0 ~len:(Array.length a) + _for_all2 p a b 0 0 ~len:(Array.length a) let rec _exists2 p a1 a2 i1 i2 ~len = len>0 && (p a1.(i1) a2.(i2) || _exists2 p a1 a2 (i1+1) (i2+1) ~len:(len-1)) -let exists2 ~f a b = - _exists2 f a b 0 0 ~len:(min (Array.length a) (Array.length b)) +let exists2 p a b = + _exists2 p a b 0 0 ~len:(min (Array.length a) (Array.length b)) let _iter2 f a b i j ~len = for o = 0 to len-1 do @@ -343,13 +342,13 @@ let _fold2 f acc a b i j ~len = in aux acc 0 -let iter2 ~f a b = +let iter2 f a b = if length a <> length b then invalid_arg "iter2"; _iter2 f a b 0 0 ~len:(Array.length a) -let fold2 ~f ~init a b = +let fold2 f acc a b = if length a <> length b then invalid_arg "fold2"; - _fold2 f init a b 0 0 ~len:(Array.length a) + _fold2 f acc a b 0 0 ~len:(Array.length a) let (--) i j = if i<=j @@ -382,9 +381,9 @@ let (--^) i j = (** all the elements of a, but the i-th, into a list *) let except_idx a i = - foldi a - ~f:(fun acc j elt -> if i = j then acc else elt::acc) - ~init:[] + foldi + (fun acc j elt -> if i = j then acc else elt::acc) + [] a let equal eq a b = let rec aux i = @@ -470,7 +469,7 @@ let pp_i ?(sep=", ") pp_item out a = pp_item k out a.(k) done -let to_seq a yield = iter ~f:yield a +let to_seq a k = iter k a let to_gen a = let k = ref 0 in diff --git a/src/core/CCArray.mli b/src/core/CCArray.mli index 58346689..39de56e6 100644 --- a/src/core/CCArray.mli +++ b/src/core/CCArray.mli @@ -31,19 +31,19 @@ val set : 'a t -> int -> 'a -> unit val length : _ t -> int -val fold : f:('a -> 'b -> 'a) -> init:'a -> 'b t -> 'a +val fold : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a -val foldi : f:('a -> int -> 'b -> 'a) -> init:'a -> 'b t -> 'a +val foldi : ('a -> int -> 'b -> 'a) -> 'a -> 'b t -> 'a (** Fold left on array, with index *) -val fold_while : f:('a -> 'b -> 'a * [`Stop | `Continue]) -> init:'a -> 'b t -> 'a +val fold_while : ('a -> 'b -> 'a * [`Stop | `Continue]) -> 'a -> 'b t -> 'a (** Fold left on array until a stop condition via [('a, `Stop)] is indicated by the accumulator @since 0.8 *) -val iter : f:('a -> unit) -> 'a t -> unit +val iter : ('a -> unit) -> 'a t -> unit -val iteri : f:(int -> 'a -> unit) -> 'a t -> unit +val iteri : (int -> 'a -> unit) -> 'a t -> unit val blit : 'a t -> int -> 'a t -> int -> int -> unit (** [blit from i into j len] copies [len] elements from the first array @@ -52,18 +52,18 @@ val blit : 'a t -> int -> 'a t -> int -> int -> unit val reverse_in_place : 'a t -> unit (** Reverse the array in place *) -val sorted : f:('a -> 'a -> int) -> 'a t -> 'a array +val sorted : ('a -> 'a -> int) -> 'a t -> 'a array (** [sorted cmp a] makes a copy of [a] and sorts it with [cmp]. @since NEXT_RELEASE *) -val sort_indices : f:('a -> 'a -> int) -> 'a t -> int array +val sort_indices : ('a -> 'a -> int) -> 'a t -> int array (** [sort_indices cmp a] returns a new array [b], with the same length as [a], such that [b.(i)] is the index of the [i]-th element of [a] in [sort cmp a]. In other words, [map (fun i -> a.(i)) (sort_indices a) = sorted cmp a]. [a] is not modified. @since NEXT_RELEASE *) -val sort_ranking : f:('a -> 'a -> int) -> 'a t -> int array +val sort_ranking : ('a -> 'a -> int) -> 'a t -> int array (** [sort_ranking cmp a] returns a new array [b], with the same length as [a], such that [b.(i)] is the position in [sorted cmp a] of the [i]-th element of [a]. @@ -75,31 +75,31 @@ val sort_ranking : f:('a -> 'a -> int) -> 'a t -> int array [lookup_exn a.(i) (sorted a) = (sorted_ranking a).(i)] @since NEXT_RELEASE *) -val find : f:('a -> 'b option) -> 'a t -> 'b option +val find : ('a -> 'b option) -> 'a t -> 'b option (** [find f a] returns [Some y] if there is an element [x] such that [f x = Some y], else it returns [None] *) -val findi : f:(int -> 'a -> 'b option) -> 'a t -> 'b option +val findi : (int -> 'a -> 'b option) -> 'a t -> 'b option (** Like {!find}, but also pass the index to the predicate function. @since 0.3.4 *) -val find_idx : f:('a -> bool) -> 'a t -> (int * 'a) option +val find_idx : ('a -> bool) -> 'a t -> (int * 'a) option (** [find_idx p x] returns [Some (i,x)] where [x] is the [i]-th element of [l], and [p x] holds. Otherwise returns [None] @since 0.3.4 *) -val lookup : ?cmp:'a ord -> key:'a -> 'a t -> int option +val lookup : ?cmp:'a ord -> 'a -> 'a t -> int option (** Lookup the index of some value in a sorted array. @return [None] if the key is not present, or [Some i] ([i] the index of the key) otherwise *) -val lookup_exn : ?cmp:'a ord -> key:'a -> 'a t -> int +val lookup_exn : ?cmp:'a ord -> 'a -> 'a t -> int (** Same as {!lookup_exn}, but @raise Not_found if the key is not present *) -val bsearch : ?cmp:('a -> 'a -> int) -> key:'a -> 'a t -> +val bsearch : ?cmp:('a -> 'a -> int) -> 'a -> 'a t -> [ `All_lower | `All_bigger | `Just_after of int | `Empty | `At of int ] -(** [bsearch ?cmp key arr] finds the index of the object [key] in the array [arr], +(** [bsearch ?cmp x arr] finds the index of the object [x] in the array [arr], provided [arr] is {b sorted} using [cmp]. If the array is not sorted, the result is not specified (may raise Invalid_argument). @@ -107,35 +107,35 @@ val bsearch : ?cmp:('a -> 'a -> int) -> key:'a -> 'a t -> (dichotomic search). @return - - [`At i] if [cmp arr.(i) key = 0] (for some i) - - [`All_lower] if all elements of [arr] are lower than [key] - - [`All_bigger] if all elements of [arr] are bigger than [key] - - [`Just_after i] if [arr.(i) < key < arr.(i+1)] + - [`At i] if [cmp arr.(i) x = 0] (for some i) + - [`All_lower] if all elements of [arr] are lower than [x] + - [`All_bigger] if all elements of [arr] are bigger than [x] + - [`Just_after i] if [arr.(i) < x < arr.(i+1)] - [`Empty] if the array is empty @raise Invalid_argument if the array is found to be unsorted w.r.t [cmp] @since 0.13 *) -val for_all : f:('a -> bool) -> 'a t -> bool +val for_all : ('a -> bool) -> 'a t -> bool -val for_all2 : f:('a -> 'b -> bool) -> 'a t -> 'b t -> bool +val for_all2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool (** Forall on pairs of arrays. @raise Invalid_argument if they have distinct lengths allow different types @since 0.20 *) -val exists : f:('a -> bool) -> 'a t -> bool +val exists : ('a -> bool) -> 'a t -> bool -val exists2 : f:('a -> 'b -> bool) -> 'a t -> 'b t -> bool +val exists2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool (** Exists on pairs of arrays. @raise Invalid_argument if they have distinct lengths allow different types @since 0.20 *) -val fold2 : f:('acc -> 'a -> 'b -> 'acc) -> init:'acc -> 'a t -> 'b t -> 'acc +val fold2 : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> 'a t -> 'b t -> 'acc (** Fold on two arrays stepwise. @raise Invalid_argument if they have distinct lengths @since 0.20 *) -val iter2 : f:('a -> 'b -> unit) -> 'a t -> 'b t -> unit +val iter2 : ('a -> 'b -> unit) -> 'a t -> 'b t -> unit (** Iterate on two arrays stepwise. @raise Invalid_argument if they have distinct lengths @since 0.20 *) @@ -162,9 +162,9 @@ val pp: ?sep:string -> 'a printer -> 'a t printer val pp_i: ?sep:string -> (int -> 'a printer) -> 'a t printer (** Print an array, giving the printing function both index and item *) -val map : f:('a -> 'b) -> 'a t -> 'b t +val map : ('a -> 'b) -> 'a t -> 'b t -val map2 : f:('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t +val map2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t (** Map on two arrays stepwise. @raise Invalid_argument if they have distinct lengths @since 0.20 *) @@ -173,14 +173,14 @@ val rev : 'a t -> 'a t (** Copy + reverse in place @since 0.20 *) -val filter : f:('a -> bool) -> 'a t -> 'a t +val filter : ('a -> bool) -> 'a t -> 'a t (** Filter elements out of the array. Only the elements satisfying the given predicate will be kept. *) -val filter_map : f:('a -> 'b option) -> 'a t -> 'b t +val filter_map : ('a -> 'b option) -> 'a t -> 'b t (** Map each element into another value, or discard it *) -val flat_map : f:('a -> 'b t) -> 'a t -> 'b array +val flat_map : ('a -> 'b t) -> 'a t -> 'b array (** Transform each element into an array, then flatten *) val (>>=) : 'a t -> ('a -> 'b t) -> 'b t diff --git a/src/core/CCArrayLabels.ml b/src/core/CCArrayLabels.ml new file mode 120000 index 00000000..607a4922 --- /dev/null +++ b/src/core/CCArrayLabels.ml @@ -0,0 +1 @@ +CCArray.ml \ No newline at end of file diff --git a/src/core/CCArrayLabels.mli b/src/core/CCArrayLabels.mli new file mode 100644 index 00000000..58346689 --- /dev/null +++ b/src/core/CCArrayLabels.mli @@ -0,0 +1,229 @@ + +(* This file is free software, part of containers. See file "license" for more details. *) + +(** {1 Array utils} *) + +type 'a sequence = ('a -> unit) -> unit +type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist] +type 'a gen = unit -> 'a option +type 'a equal = 'a -> 'a -> bool +type 'a ord = 'a -> 'a -> int +type 'a random_gen = Random.State.t -> 'a +type 'a printer = Format.formatter -> 'a -> unit + +(** {2 Arrays} *) + +type 'a t = 'a array + +val empty : 'a t + +val equal : 'a equal -> 'a t equal + +val compare : 'a ord -> 'a t ord + +val get : 'a t -> int -> 'a + +val get_safe : 'a t -> int -> 'a option +(** [get_safe a i] returns [Some a.(i)] if [i] is a valid index + @since 0.18 *) + +val set : 'a t -> int -> 'a -> unit + +val length : _ t -> int + +val fold : f:('a -> 'b -> 'a) -> init:'a -> 'b t -> 'a + +val foldi : f:('a -> int -> 'b -> 'a) -> init:'a -> 'b t -> 'a +(** Fold left on array, with index *) + +val fold_while : f:('a -> 'b -> 'a * [`Stop | `Continue]) -> init:'a -> 'b t -> 'a +(** Fold left on array until a stop condition via [('a, `Stop)] is + indicated by the accumulator + @since 0.8 *) + +val iter : f:('a -> unit) -> 'a t -> unit + +val iteri : f:(int -> 'a -> unit) -> 'a t -> unit + +val blit : 'a t -> int -> 'a t -> int -> int -> unit +(** [blit from i into j len] copies [len] elements from the first array + to the second. See {!Array.blit}. *) + +val reverse_in_place : 'a t -> unit +(** Reverse the array in place *) + +val sorted : f:('a -> 'a -> int) -> 'a t -> 'a array +(** [sorted cmp a] makes a copy of [a] and sorts it with [cmp]. + @since NEXT_RELEASE *) + +val sort_indices : f:('a -> 'a -> int) -> 'a t -> int array +(** [sort_indices cmp a] returns a new array [b], with the same length as [a], + such that [b.(i)] is the index of the [i]-th element of [a] in [sort cmp a]. + In other words, [map (fun i -> a.(i)) (sort_indices a) = sorted cmp a]. + [a] is not modified. + @since NEXT_RELEASE *) + +val sort_ranking : f:('a -> 'a -> int) -> 'a t -> int array +(** [sort_ranking cmp a] returns a new array [b], with the same length as [a], + such that [b.(i)] is the position in [sorted cmp a] of the [i]-th + element of [a]. + [a] is not modified. + + In other words, [map (fun i -> (sorted cmp a).(i)) (sort_ranking cmp a) = a]. + + Without duplicates, we also have + [lookup_exn a.(i) (sorted a) = (sorted_ranking a).(i)] + @since NEXT_RELEASE *) + +val find : f:('a -> 'b option) -> 'a t -> 'b option +(** [find f a] returns [Some y] if there is an element [x] such + that [f x = Some y], else it returns [None] *) + +val findi : f:(int -> 'a -> 'b option) -> 'a t -> 'b option +(** Like {!find}, but also pass the index to the predicate function. + @since 0.3.4 *) + +val find_idx : f:('a -> bool) -> 'a t -> (int * 'a) option +(** [find_idx p x] returns [Some (i,x)] where [x] is the [i]-th element of [l], + and [p x] holds. Otherwise returns [None] + @since 0.3.4 *) + +val lookup : ?cmp:'a ord -> key:'a -> 'a t -> int option +(** Lookup the index of some value in a sorted array. + @return [None] if the key is not present, or + [Some i] ([i] the index of the key) otherwise *) + +val lookup_exn : ?cmp:'a ord -> key:'a -> 'a t -> int +(** Same as {!lookup_exn}, but + @raise Not_found if the key is not present *) + +val bsearch : ?cmp:('a -> 'a -> int) -> key:'a -> 'a t -> + [ `All_lower | `All_bigger | `Just_after of int | `Empty | `At of int ] +(** [bsearch ?cmp key arr] finds the index of the object [key] in the array [arr], + provided [arr] is {b sorted} using [cmp]. If the array is not sorted, + the result is not specified (may raise Invalid_argument). + + Complexity: O(log n) where n is the length of the array + (dichotomic search). + + @return + - [`At i] if [cmp arr.(i) key = 0] (for some i) + - [`All_lower] if all elements of [arr] are lower than [key] + - [`All_bigger] if all elements of [arr] are bigger than [key] + - [`Just_after i] if [arr.(i) < key < arr.(i+1)] + - [`Empty] if the array is empty + + @raise Invalid_argument if the array is found to be unsorted w.r.t [cmp] + @since 0.13 *) + +val for_all : f:('a -> bool) -> 'a t -> bool + +val for_all2 : f:('a -> 'b -> bool) -> 'a t -> 'b t -> bool +(** Forall on pairs of arrays. + @raise Invalid_argument if they have distinct lengths + allow different types @since 0.20 *) + +val exists : f:('a -> bool) -> 'a t -> bool + +val exists2 : f:('a -> 'b -> bool) -> 'a t -> 'b t -> bool +(** Exists on pairs of arrays. + @raise Invalid_argument if they have distinct lengths + allow different types @since 0.20 *) + +val fold2 : f:('acc -> 'a -> 'b -> 'acc) -> init:'acc -> 'a t -> 'b t -> 'acc +(** Fold on two arrays stepwise. + @raise Invalid_argument if they have distinct lengths + @since 0.20 *) + +val iter2 : f:('a -> 'b -> unit) -> 'a t -> 'b t -> unit +(** Iterate on two arrays stepwise. + @raise Invalid_argument if they have distinct lengths + @since 0.20 *) + +val shuffle : 'a t -> unit +(** Shuffle randomly the array, in place *) + +val shuffle_with : Random.State.t -> 'a t -> unit +(** Like shuffle but using a specialized random state *) + +val random_choose : 'a t -> 'a random_gen +(** Choose an element randomly. + @raise Not_found if the array/slice is empty *) + +val to_seq : 'a t -> 'a sequence +val to_gen : 'a t -> 'a gen +val to_klist : 'a t -> 'a klist + +(** {2 IO} *) + +val pp: ?sep:string -> 'a printer -> 'a t printer +(** Print an array of items with printing function *) + +val pp_i: ?sep:string -> (int -> 'a printer) -> 'a t printer +(** Print an array, giving the printing function both index and item *) + +val map : f:('a -> 'b) -> 'a t -> 'b t + +val map2 : f:('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t +(** Map on two arrays stepwise. + @raise Invalid_argument if they have distinct lengths + @since 0.20 *) + +val rev : 'a t -> 'a t +(** Copy + reverse in place + @since 0.20 *) + +val filter : f:('a -> bool) -> 'a t -> 'a t +(** Filter elements out of the array. Only the elements satisfying + the given predicate will be kept. *) + +val filter_map : f:('a -> 'b option) -> 'a t -> 'b t +(** Map each element into another value, or discard it *) + +val flat_map : f:('a -> 'b t) -> 'a t -> 'b array +(** Transform each element into an array, then flatten *) + +val (>>=) : 'a t -> ('a -> 'b t) -> 'b t +(** Infix version of {!flat_map} *) + +val (>>|) : 'a t -> ('a -> 'b) -> 'b t +(** Infix version of {!map} + @since 0.8 *) + +val (>|=) : 'a t -> ('a -> 'b) -> 'b t +(** Infix version of {!map} + @since 0.8 *) + +val except_idx : 'a t -> int -> 'a list +(** Remove given index, obtaining the list of the other elements *) + +val (--) : int -> int -> int t +(** Range array *) + +val (--^) : int -> int -> int t +(** Range array, excluding right bound + @since 0.17 *) + +val random : 'a random_gen -> 'a t random_gen +val random_non_empty : 'a random_gen -> 'a t random_gen +val random_len : int -> 'a random_gen -> 'a t random_gen + +(** {2 Generic Functions} *) + +module type MONO_ARRAY = sig + type elt + type t + + val length : t -> int + + val get : t -> int -> elt + + val set : t -> int -> elt -> unit +end + +val sort_generic : + (module MONO_ARRAY with type t = 'arr and type elt = 'elt) -> + ?cmp:('elt -> 'elt -> int) -> 'arr -> unit +(** Sort the array, without allocating (eats stack space though). Performance + might be lower than {!Array.sort}. + @since 0.14 *) diff --git a/src/core/CCList.ml b/src/core/CCList.ml index 163ab17f..65b55f72 100644 --- a/src/core/CCList.ml +++ b/src/core/CCList.ml @@ -18,7 +18,7 @@ let is_empty = function (* max depth for direct recursion *) let direct_depth_default_ = 1000 -let map ~f l = +let map f l = let rec direct f i l = match l with | [] -> [] | [x] -> [f x] @@ -40,7 +40,7 @@ let map ~f l = List.rev (List.rev_map f l) = map f l) *) -let (>|=) l f = map ~f:f l +let (>|=) l f = map f l let direct_depth_append_ = 10_000 @@ -78,7 +78,7 @@ let cons_maybe o l = match o with let direct_depth_filter_ = 10_000 -let filter ~f l = +let filter p l = let rec direct i p l = match l with | [] -> [] | _ when i=0 -> safe p l [] @@ -89,7 +89,7 @@ let filter ~f l = | x::l' when not (p x) -> safe p l' acc | x::l' -> safe p l' (x::acc) in - direct direct_depth_filter_ f l + direct direct_depth_filter_ p l (*$= & ~printer:CCInt.to_string 500 (filter (fun x->x mod 2 = 0) (1 -- 1000) |> List.length) @@ -122,38 +122,37 @@ let fold_right f l acc = l = fold_right (fun x y->x::y) l []) *) -let rec fold_while ~f ~init:acc = function +let rec fold_while f acc = function | [] -> acc | e::l -> let acc, cont = f acc e in match cont with | `Stop -> acc - | `Continue -> fold_while ~f ~init:acc l + | `Continue -> fold_while f acc l (*$T - fold_while ~f:(fun acc b -> if b then acc+1, `Continue else acc, `Stop) \ - ~init:0 [true;true;false;true] = 2 + fold_while (fun acc b -> if b then acc+1, `Continue else acc, `Stop) 0 [true;true;false;true] = 2 *) -let fold_map ~f ~init l = +let fold_map f acc l = let rec aux f acc map_acc l = match l with | [] -> acc, List.rev map_acc | x :: l' -> let acc, y = f acc x in aux f acc (y :: map_acc) l' in - aux f init [] l + aux f acc [] l (*$= (6, ["1"; "2"; "3"]) \ - (fold_map ~f:(fun acc x->acc+x, string_of_int x) ~init:0 [1;2;3]) + (fold_map (fun acc x->acc+x, string_of_int x) 0 [1;2;3]) *) (*$Q Q.(list int) (fun l -> \ - fold_map ~f:(fun acc x -> x::acc, x) ~init:[] l = (List.rev l, l)) + fold_map (fun acc x -> x::acc, x) [] l = (List.rev l, l)) *) -let fold_map2 ~f ~init l1 l2 = +let fold_map2 f acc l1 l2 = let rec aux f acc map_acc l1 l2 = match l1, l2 with | [], [] -> acc, List.rev map_acc | [], _ @@ -162,56 +161,56 @@ let fold_map2 ~f ~init l1 l2 = let acc, y = f acc x1 x2 in aux f acc (y :: map_acc) l1' l2' in - aux f init [] l1 l2 + aux f acc [] l1 l2 (*$= (310, ["1 10"; "2 0"; "3 100"]) \ - (fold_map2 ~f:(fun acc x y->acc+x*y, string_of_int x ^ " " ^ string_of_int y) \ - ~init:0 [1;2;3] [10;0;100]) + (fold_map2 (fun acc x y->acc+x*y, string_of_int x ^ " " ^ string_of_int y) \ + 0 [1;2;3] [10;0;100]) *) (*$T - (try ignore (fold_map2 ~f:(fun _ _ _ -> assert false) ~init:42 [] [1]); false \ + (try ignore (fold_map2 (fun _ _ _ -> assert false) 42 [] [1]); false \ with Invalid_argument _ -> true) *) -let fold_filter_map ~f ~init l = +let fold_filter_map f acc l = let rec aux f acc map_acc l = match l with | [] -> acc, List.rev map_acc | x :: l' -> let acc, y = f acc x in aux f acc (cons_maybe y map_acc) l' in - aux f init [] l + aux f acc [] l (*$= & ~printer:Q.Print.(pair int (list int)) (List.fold_left (+) 0 (1--10), [2;4;6;8;10]) \ - (fold_filter_map ~f:(fun acc x -> acc+x, if x mod 2 = 0 then Some x else None) \ - ~init:0 (1--10)) + (fold_filter_map (fun acc x -> acc+x, if x mod 2 = 0 then Some x else None) \ + 0 (1--10)) *) -let fold_flat_map ~f ~init l = +let fold_flat_map f acc l = let rec aux f acc map_acc l = match l with | [] -> acc, List.rev map_acc | x :: l' -> let acc, y = f acc x in aux f acc (List.rev_append y map_acc) l' in - aux f init [] l + aux f acc [] l (*$= (6, ["1"; "a1"; "2"; "a2"; "3"; "a3"]) \ (let pf = Printf.sprintf in \ - fold_flat_map ~f:(fun acc x->acc+x, [pf "%d" x; pf "a%d" x]) ~init:0 [1;2;3]) + fold_flat_map (fun acc x->acc+x, [pf "%d" x; pf "a%d" x]) 0 [1;2;3]) *) (*$Q Q.(list int) (fun l -> \ - fold_flat_map ~f:(fun acc x -> x::acc, [x;x+10]) ~init:[] l = \ - (List.rev l, flat_map ~f:(fun x->[x;x+10]) l) ) + fold_flat_map (fun acc x -> x::acc, [x;x+10]) [] l = \ + (List.rev l, flat_map (fun x->[x;x+10]) l) ) *) -let init len ~f = +let init len f = let rec init_rec acc i f = if i=0 then f i :: acc else init_rec (f i :: acc) (i-1) f @@ -221,9 +220,9 @@ let init len ~f = else init_rec [] (len-1) f (*$T - init 0 ~f:(fun _ -> 0) = [] - init 1 ~f:(fun x->x) = [0] - init 1000 ~f:(fun x->x) = 0--999 + init 0 (fun _ -> 0) = [] + init 1 (fun x->x) = [0] + init 1000 (fun x->x) = 0--999 *) let rec compare f l1 l2 = match l1, l2 with @@ -243,7 +242,7 @@ let rec equal f l1 l2 = match l1, l2 with equal CCInt.equal (1--1_000_000) (1--1_000_000) *) -let flat_map ~f l = +let flat_map f l = let rec aux f l kont = match l with | [] -> kont [] | x::l' -> @@ -267,19 +266,19 @@ let flatten l = fold_right append l [] (*$T flatten [[1]; [2;3;4]; []; []; [5;6]] = 1--6 - flatten (init 300_001 ~f:(fun x->[x])) = 0--300_000 + flatten (init 300_001 (fun x->[x])) = 0--300_000 *) -let product ~f l1 l2 = - flat_map ~f:(fun x -> map ~f:(fun y -> f x y) l2) l1 +let product f l1 l2 = + flat_map (fun x -> map (fun y -> f x y) l2) l1 -let fold_product ~f ~init l1 l2 = +let fold_product f acc l1 l2 = List.fold_left (fun acc x1 -> List.fold_left (fun acc x2 -> f acc x1 x2) - acc l2) - init l1 + acc l2 + ) acc l1 let diagonal l = let rec gen acc l = match l with @@ -297,7 +296,7 @@ let diagonal l = diagonal [1;2;3] |> List.sort Pervasives.compare = [1, 2; 1, 3; 2, 3] *) -let partition_map ~f l = +let partition_map f l = let rec iter f l1 l2 l = match l with | [] -> List.rev l1, List.rev l2 | x :: tl -> @@ -310,11 +309,11 @@ let partition_map ~f l = (*$R let l1, l2 = - partition_map ~f:(function + partition_map (function | n when n = 0 -> `Drop | n when n mod 2 = 0 -> `Left n - | n -> `Right n) - [0;1;2;3;4] + | n -> `Right n + ) [0;1;2;3;4] in assert_equal [2;4] l1; assert_equal [1;3] l2 @@ -322,13 +321,13 @@ let partition_map ~f l = let return x = [x] -let (>>=) l f = flat_map ~f l +let (>>=) l f = flat_map f l -let (<$>) f x = map ~f x +let (<$>) = map let pure = return -let (<*>) funs l = product ~f:(fun f x -> f x) funs l +let (<*>) funs l = product (fun f x -> f x) funs l let sorted_merge ?(cmp=Pervasives.compare) l1 l2 = let rec recurse cmp acc l1 l2 = match l1,l2 with @@ -531,7 +530,7 @@ let split = take_drop l1 @ l2 = l ) *) -let take_while ~f l = +let take_while p l = let rec direct i p l = match l with | [] -> [] | _ when i=0 -> safe p [] l @@ -542,13 +541,13 @@ let take_while ~f l = | x :: l' -> if p x then safe p (x::acc) l' else List.rev acc in - direct direct_depth_default_ f l + direct direct_depth_default_ p l (*$T - take_while ~f:(fun x->x<10) (1 -- 20) = (1--9) - take_while ~f:(fun x->x <> 0) [0;1;2;3] = [] - take_while ~f:(fun _ -> true) [] = [] - take_while ~f:(fun _ -> true) (1--10) = (1--10) + take_while (fun x->x<10) (1 -- 20) = (1--9) + take_while (fun x->x <> 0) [0;1;2;3] = [] + take_while (fun _ -> true) [] = [] + take_while (fun _ -> true) (1--10) = (1--10) *) (*$Q @@ -557,9 +556,9 @@ let take_while ~f l = List.for_all f l1) *) -let rec drop_while ~f l = match l with +let rec drop_while p l = match l with | [] -> [] - | x :: l' -> if f x then drop_while ~f l' else l + | x :: l' -> if p x then drop_while p l' else l (*$Q Q.(pair (fun1 small_int bool) (list small_int)) (fun (f,l) -> \ @@ -588,23 +587,23 @@ let rec last_opt = function None (last_opt []) *) -let rec find_pred ~f l = match l with +let rec find_pred p l = match l with | [] -> None - | x :: _ when f x -> Some x - | _ :: tl -> find_pred ~f tl + | x :: _ when p x -> Some x + | _ :: tl -> find_pred p tl -let find_pred_exn ~f l = match find_pred ~f l with +let find_pred_exn p l = match find_pred p l with | None -> raise Not_found | Some x -> x (*$T - find_pred ~f:((=) 4) [1;2;5;4;3;0] = Some 4 - find_pred ~f:(fun _ -> true) [] = None - find_pred ~f:(fun _ -> false) (1 -- 10) = None - find_pred ~f:(fun x -> x < 10) (1 -- 9) = Some 1 + find_pred ((=) 4) [1;2;5;4;3;0] = Some 4 + find_pred (fun _ -> true) [] = None + find_pred (fun _ -> false) (1 -- 10) = None + find_pred (fun x -> x < 10) (1 -- 9) = Some 1 *) -let find_mapi ~f l = +let find_mapi f l = let rec aux f i = function | [] -> None | x::l' -> @@ -613,32 +612,32 @@ let find_mapi ~f l = | None -> aux f (i+1) l' in aux f 0 l -let find_map ~f l = find_mapi ~f:(fun _ -> f) l +let find_map f l = find_mapi (fun _ -> f) l let find = find_map let findi = find_mapi -let find_idx ~f l = find_mapi ~f:(fun i x -> if f x then Some (i, x) else None) l +let find_idx p l = find_mapi (fun i x -> if p x then Some (i, x) else None) l (*$T find (fun x -> if x=3 then Some "a" else None) [1;2;3;4] = Some "a" find (fun x -> if x=3 then Some "a" else None) [1;2;4;5] = None *) -let remove ?(eq=(=)) ~key l = +let remove ?(eq=(=)) ~x l = let rec remove' eq x acc l = match l with | [] -> List.rev acc | y :: tail when eq x y -> remove' eq x acc tail | y :: tail -> remove' eq x (y::acc) tail in - remove' eq key [] l + remove' eq x [] l (*$T - remove ~key:1 [2;1;3;3;2;1] = [2;3;3;2] - remove ~key:10 [1;2;3] = [1;2;3] + remove ~x:1 [2;1;3;3;2;1] = [2;3;3;2] + remove ~x:10 [1;2;3] = [1;2;3] *) -let filter_map ~f l = +let filter_map f l = let rec recurse acc l = match l with | [] -> List.rev acc | x::l' -> @@ -719,32 +718,32 @@ let inter ?(eq=(=)) l1 l2 = inter [1;2;4] [2;3;4;5] = [2;4] *) -let mapi ~f l = +let mapi f l = let r = ref 0 in - map l - ~f:(fun x -> + map + (fun x -> let y = f !r x in - incr r; - y) + incr r; y + ) l (*$T - mapi ~f:(fun i x -> i*x) [10;10;10] = [0;10;20] + mapi (fun i x -> i*x) [10;10;10] = [0;10;20] *) -let iteri ~f l = +let iteri f l = let rec aux f i l = match l with | [] -> () | x::l' -> f i x; aux f (i+1) l' in aux f 0 l -let foldi ~f ~init l = +let foldi f acc l = let rec foldi f acc i l = match l with | [] -> acc | x::l' -> let acc = f acc i x in foldi f acc (i+1) l' in - foldi f init 0 l + foldi f acc 0 l let rec get_at_idx_exn i l = match l with | [] -> raise Not_found @@ -1019,7 +1018,7 @@ end module Traverse(M : MONAD) = struct open M - let map_m ~f l = + let map_m f l = let rec aux f acc l = match l with | [] -> return (List.rev acc) | x::tail -> @@ -1027,23 +1026,23 @@ module Traverse(M : MONAD) = struct aux f (x' :: acc) tail in aux f [] l - let rec map_m_par ~f l = match l with + let rec map_m_par f l = match l with | [] -> M.return [] | x::tl -> let x' = f x in - let tl' = map_m_par ~f tl in + let tl' = map_m_par f tl in x' >>= fun x' -> tl' >>= fun tl' -> M.return (x'::tl') - let sequence_m l = map_m l ~f:(fun x->x) + let sequence_m l = map_m (fun x->x) l - let rec fold_m ~f ~init l = match l with - | [] -> return init + let rec fold_m f acc l = match l with + | [] -> return acc | x :: l' -> - f init x + f acc x >>= fun acc' -> - fold_m ~f ~init:acc' l' + fold_m f acc' l' end (** {2 Conversions} *) @@ -1055,7 +1054,7 @@ type 'a printer = Format.formatter -> 'a -> unit type 'a random_gen = Random.State.t -> 'a let random_len len g st = - init len ~f:(fun _ -> g st) + init len (fun _ -> g st) (*$T random_len 10 CCInt.random_small (Random.State.make [||]) |> List.length = 10 @@ -1077,7 +1076,7 @@ let random_choose l = match l with let i = Random.State.int st len in List.nth l i -let random_sequence l st = map l ~f:(fun g -> g st) +let random_sequence l st = map (fun g -> g st) l let to_seq l k = List.iter k l let of_seq seq = diff --git a/src/core/CCList.mli b/src/core/CCList.mli index 5d8b01c4..b6f01ecc 100644 --- a/src/core/CCList.mli +++ b/src/core/CCList.mli @@ -11,7 +11,7 @@ val is_empty : _ t -> bool (** [is_empty l] returns [true] iff [l = []] @since 0.11 *) -val map : f:('a -> 'b) -> 'a t -> 'b t +val map : ('a -> 'b) -> 'a t -> 'b t (** Safe version of map *) val (>|=) : 'a t -> ('a -> 'b) -> 'b t @@ -32,38 +32,38 @@ val cons_maybe : 'a option -> 'a t -> 'a t val (@) : 'a t -> 'a t -> 'a t -val filter : f:('a -> bool) -> 'a t -> 'a t +val filter : ('a -> bool) -> 'a t -> 'a t (** Safe version of {!List.filter} *) val fold_right : ('a -> 'b -> 'b) -> 'a t -> 'b -> 'b (** Safe version of [fold_right] *) -val fold_while : f:('a -> 'b -> 'a * [`Stop | `Continue]) -> init:'a -> 'b t -> 'a +val fold_while : ('a -> 'b -> 'a * [`Stop | `Continue]) -> 'a -> 'b t -> 'a (** Fold until a stop condition via [('a, `Stop)] is indicated by the accumulator @since 0.8 *) -val fold_map : f:('acc -> 'a -> 'acc * 'b) -> init:'acc -> 'a list -> 'acc * 'b list +val fold_map : ('acc -> 'a -> 'acc * 'b) -> 'acc -> 'a list -> 'acc * 'b list (** [fold_map f acc l] is a [fold_left]-like function, but it also maps the list to another list. @since 0.14 *) -val fold_map2 : f:('acc -> 'a -> 'b -> 'acc * 'c) -> init:'acc -> 'a list -> 'b list -> 'acc * 'c list +val fold_map2 : ('acc -> 'a -> 'b -> 'acc * 'c) -> 'acc -> 'a list -> 'b list -> 'acc * 'c list (** [fold_map2] is to [fold_map] what [List.map2] is to [List.map]. @raise Invalid_argument if the lists do not have the same length @since 0.16 *) -val fold_filter_map : f:('acc -> 'a -> 'acc * 'b option) -> init:'acc -> 'a list -> 'acc * 'b list +val fold_filter_map : ('acc -> 'a -> 'acc * 'b option) -> 'acc -> 'a list -> 'acc * 'b list (** [fold_filter_map f acc l] is a [fold_left]-like function, but also generates a list of output in a way similar to {!filter_map} @since 0.17 *) -val fold_flat_map : f:('acc -> 'a -> 'acc * 'b list) -> init:'acc -> 'a list -> 'acc * 'b list +val fold_flat_map : ('acc -> 'a -> 'acc * 'b list) -> 'acc -> 'a list -> 'acc * 'b list (** [fold_flat_map f acc l] is a [fold_left]-like function, but it also maps the list to a list of lists that is then [flatten]'d.. @since 0.14 *) -val init : int -> f:(int -> 'a) -> 'a t +val init : int -> (int -> 'a) -> 'a t (** Similar to {!Array.init} @since 0.6 *) @@ -71,23 +71,23 @@ val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool -val flat_map : f:('a -> 'b t) -> 'a t -> 'b t +val flat_map : ('a -> 'b t) -> 'a t -> 'b t (** Map and flatten at the same time (safe). Evaluation order is not guaranteed. *) val flatten : 'a t t -> 'a t (** Safe flatten *) -val product : f:('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t +val product : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t (** Cartesian product of the two lists, with the given combinator *) -val fold_product : f:('c -> 'a -> 'b -> 'c) -> init:'c -> 'a t -> 'b t -> 'c +val fold_product : ('c -> 'a -> 'b -> 'c) -> 'c -> 'a t -> 'b t -> 'c (** Fold on the cartesian product *) val diagonal : 'a t -> ('a * 'a) t (** All pairs of distinct positions of the list. [list_diagonal l] will return the list of [List.nth i l, List.nth j l] if [i < j]. *) -val partition_map : f:('a -> [<`Left of 'b | `Right of 'c | `Drop]) -> +val partition_map : ('a -> [<`Left of 'b | `Right of 'c | `Drop]) -> 'a list -> 'b list * 'c list (** [partition_map f l] maps [f] on [l] and gather results in lists: - if [f x = `Left y], adds [y] to the first list @@ -120,10 +120,10 @@ val take_drop : int -> 'a t -> 'a t * 'a t (** [take_drop n l] returns [l1, l2] such that [l1 @ l2 = l] and [length l1 = min (length l) n] *) -val take_while : f:('a -> bool) -> 'a t -> 'a t +val take_while : ('a -> bool) -> 'a t -> 'a t (** @since 0.13 *) -val drop_while : f:('a -> bool) -> 'a t -> 'a t +val drop_while : ('a -> bool) -> 'a t -> 'a t (** @since 0.13 *) val split : int -> 'a t -> 'a t * 'a t @@ -142,44 +142,43 @@ val last_opt : 'a t -> 'a option (** Last element. @since 0.20 *) -val find_pred : f:('a -> bool) -> 'a t -> 'a option +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 0.11 *) -val find_pred_exn : f:('a -> bool) -> 'a t -> 'a +val find_pred_exn : ('a -> bool) -> 'a t -> 'a (** Unsafe version of {!find_pred} @raise Not_found if no such element is found @since 0.11 *) -val find_map : f:('a -> 'b option) -> 'a t -> 'b option +val find_map : ('a -> 'b option) -> 'a t -> 'b option (** [find_map f l] traverses [l], applying [f] to each element. If for some element [x], [f x = Some y], then [Some y] is returned. Otherwise the call returns [None] @since 0.11 *) -(* TODO remove *) -val find : f:('a -> 'b option) -> 'a list -> 'b option +val find : ('a -> 'b option) -> 'a list -> 'b option (** @deprecated since 0.11 in favor of {!find_map}, for the name is too confusing *) -val find_mapi : f:(int -> 'a -> 'b option) -> 'a t -> 'b option +val find_mapi : (int -> 'a -> 'b option) -> 'a t -> 'b option (** Like {!find_map}, but also pass the index to the predicate function. @since 0.11 *) -val findi : f:(int -> 'a -> 'b option) -> 'a t -> 'b option +val findi : (int -> 'a -> 'b option) -> 'a t -> 'b option (** @deprecated since 0.11 in favor of {!find_mapi}, name is too confusing @since 0.3.4 *) -val find_idx : f:('a -> bool) -> 'a t -> (int * 'a) option +val find_idx : ('a -> bool) -> 'a t -> (int * 'a) option (** [find_idx p x] returns [Some (i,x)] where [x] is the [i]-th element of [l], and [p x] holds. Otherwise returns [None] *) -val remove : ?eq:('a -> 'a -> bool) -> key:'a -> 'a t -> 'a t -(** [remove ~key l] removes every instance of [key] from [l]. Tailrec. +val remove : ?eq:('a -> 'a -> bool) -> x:'a -> 'a t -> 'a t +(** [remove ~x l] removes every instance of [x] from [l]. Tailrec. @param eq equality function @since 0.11 *) -val filter_map : f:('a -> 'b option) -> 'a t -> 'b t +val filter_map : ('a -> 'b option) -> 'a t -> 'b t (** Map and remove elements at the same time *) val sorted_merge : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list @@ -225,11 +224,11 @@ val group_succ : ?eq:('a -> 'a -> bool) -> 'a list -> 'a list list (** {2 Indices} *) -val mapi : f:(int -> 'a -> 'b) -> 'a t -> 'b t +val mapi : (int -> 'a -> 'b) -> 'a t -> 'b t -val iteri : f:(int -> 'a -> unit) -> 'a t -> unit +val iteri : (int -> 'a -> unit) -> 'a t -> unit -val foldi : f:('b -> int -> 'a -> 'b) -> init:'b -> 'a t -> 'b +val foldi : ('b -> int -> 'a -> 'b) -> 'b -> 'a t -> 'b (** Fold on list, with index *) val get_at_idx : int -> 'a t -> 'a option @@ -380,11 +379,11 @@ end module Traverse(M : MONAD) : sig val sequence_m : 'a M.t t -> 'a t M.t - val fold_m : f:('b -> 'a -> 'b M.t) -> init:'b -> 'a t -> 'b M.t + val fold_m : ('b -> 'a -> 'b M.t) -> 'b -> 'a t -> 'b M.t - val map_m : f:('a -> 'b M.t) -> 'a t -> 'b t M.t + val map_m : ('a -> 'b M.t) -> 'a t -> 'b t M.t - val map_m_par : f:('a -> 'b M.t) -> 'a t -> 'b t M.t + val map_m_par : ('a -> 'b M.t) -> 'a t -> 'b t M.t (** Same as {!map_m} but [map_m_par f (x::l)] evaluates [f x] and [f l] "in parallel" before combining their result (for instance in Lwt). *) diff --git a/src/core/CCListLabels.ml b/src/core/CCListLabels.ml new file mode 120000 index 00000000..8e52dced --- /dev/null +++ b/src/core/CCListLabels.ml @@ -0,0 +1 @@ +CCList.ml \ No newline at end of file diff --git a/src/core/CCListLabels.mli b/src/core/CCListLabels.mli new file mode 100644 index 00000000..5d8b01c4 --- /dev/null +++ b/src/core/CCListLabels.mli @@ -0,0 +1,441 @@ + +(* This file is free software, part of containers. See file "license" for more details. *) + +(** {1 complements to list} *) + +type 'a t = 'a list + +val empty : 'a t + +val is_empty : _ t -> bool +(** [is_empty l] returns [true] iff [l = []] + @since 0.11 *) + +val map : f:('a -> 'b) -> 'a t -> 'b t +(** Safe version of map *) + +val (>|=) : 'a t -> ('a -> 'b) -> 'b t +(** Infix version of [map] with reversed arguments + @since 0.5 *) + +val cons : 'a -> 'a t -> 'a t +(** [cons x l] is [x::l] + @since 0.12 *) + +val append : 'a t -> 'a t -> 'a t +(** Safe version of append *) + +val cons_maybe : 'a option -> 'a t -> 'a t +(** [cons_maybe (Some x) l] is [x :: l] + [cons_maybe None l] is [l] + @since 0.13 *) + +val (@) : 'a t -> 'a t -> 'a t + +val filter : f:('a -> bool) -> 'a t -> 'a t +(** Safe version of {!List.filter} *) + +val fold_right : ('a -> 'b -> 'b) -> 'a t -> 'b -> 'b +(** Safe version of [fold_right] *) + +val fold_while : f:('a -> 'b -> 'a * [`Stop | `Continue]) -> init:'a -> 'b t -> 'a +(** Fold until a stop condition via [('a, `Stop)] is + indicated by the accumulator + @since 0.8 *) + +val fold_map : f:('acc -> 'a -> 'acc * 'b) -> init:'acc -> 'a list -> 'acc * 'b list +(** [fold_map f acc l] is a [fold_left]-like function, but it also maps the + list to another list. + @since 0.14 *) + +val fold_map2 : f:('acc -> 'a -> 'b -> 'acc * 'c) -> init:'acc -> 'a list -> 'b list -> 'acc * 'c list +(** [fold_map2] is to [fold_map] what [List.map2] is to [List.map]. + @raise Invalid_argument if the lists do not have the same length + @since 0.16 *) + +val fold_filter_map : f:('acc -> 'a -> 'acc * 'b option) -> init:'acc -> 'a list -> 'acc * 'b list +(** [fold_filter_map f acc l] is a [fold_left]-like function, but also + generates a list of output in a way similar to {!filter_map} + @since 0.17 *) + +val fold_flat_map : f:('acc -> 'a -> 'acc * 'b list) -> init:'acc -> 'a list -> 'acc * 'b list +(** [fold_flat_map f acc l] is a [fold_left]-like function, but it also maps the + list to a list of lists that is then [flatten]'d.. + @since 0.14 *) + +val init : int -> f:(int -> 'a) -> 'a t +(** Similar to {!Array.init} + @since 0.6 *) + +val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int + +val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool + +val flat_map : f:('a -> 'b t) -> 'a t -> 'b t +(** Map and flatten at the same time (safe). Evaluation order is not guaranteed. *) + +val flatten : 'a t t -> 'a t +(** Safe flatten *) + +val product : f:('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t +(** Cartesian product of the two lists, with the given combinator *) + +val fold_product : f:('c -> 'a -> 'b -> 'c) -> init:'c -> 'a t -> 'b t -> 'c +(** Fold on the cartesian product *) + +val diagonal : 'a t -> ('a * 'a) t +(** All pairs of distinct positions of the list. [list_diagonal l] will + return the list of [List.nth i l, List.nth j l] if [i < j]. *) + +val partition_map : f:('a -> [<`Left of 'b | `Right of 'c | `Drop]) -> + 'a list -> 'b list * 'c list +(** [partition_map f l] maps [f] on [l] and gather results in lists: + - if [f x = `Left y], adds [y] to the first list + - if [f x = `Right z], adds [z] to the second list + - if [f x = `Drop], ignores [x] + @since 0.11 *) + +val pure : 'a -> 'a t + +val (<*>) : ('a -> 'b) t -> 'a t -> 'b t + +val (<$>) : ('a -> 'b) -> 'a t -> 'b t + +val return : 'a -> 'a t + +val (>>=) : 'a t -> ('a -> 'b t) -> 'b t + +val take : int -> 'a t -> 'a t +(** Take the [n] first elements, drop the rest *) + +val drop : int -> 'a t -> 'a t +(** Drop the [n] first elements, keep the rest *) + +val hd_tl : 'a t -> 'a * 'a t +(** [hd_tl (x :: l)] returns [hd, l]. + @raise Failure if the list is empty + @since 0.16 *) + +val take_drop : int -> 'a t -> 'a t * 'a t +(** [take_drop n l] returns [l1, l2] such that [l1 @ l2 = l] and + [length l1 = min (length l) n] *) + +val take_while : f:('a -> bool) -> 'a t -> 'a t +(** @since 0.13 *) + +val drop_while : f:('a -> bool) -> 'a t -> 'a t +(** @since 0.13 *) + +val split : int -> 'a t -> 'a t * 'a t +(** Synonym to {!take_drop} + @deprecated since 0.13: conflict with the {!List.split} standard function *) + +val last : int -> 'a t -> 'a t +(** [last n l] takes the last [n] elements of [l] (or less if + [l] doesn't have that many elements *) + +val head_opt : 'a t -> 'a option +(** First element. + @since 0.20 *) + +val last_opt : 'a t -> 'a option +(** Last element. + @since 0.20 *) + +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 0.11 *) + +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 0.11 *) + +val find_map : f:('a -> 'b option) -> 'a t -> 'b option +(** [find_map f l] traverses [l], applying [f] to each element. If for + some element [x], [f x = Some y], then [Some y] is returned. Otherwise + the call returns [None] + @since 0.11 *) + +(* TODO remove *) +val find : f:('a -> 'b option) -> 'a list -> 'b option +(** @deprecated since 0.11 in favor of {!find_map}, for the name is too confusing *) + +val find_mapi : f:(int -> 'a -> 'b option) -> 'a t -> 'b option +(** Like {!find_map}, but also pass the index to the predicate function. + @since 0.11 *) + +val findi : f:(int -> 'a -> 'b option) -> 'a t -> 'b option +(** @deprecated since 0.11 in favor of {!find_mapi}, name is too confusing + @since 0.3.4 *) + +val find_idx : f:('a -> bool) -> 'a t -> (int * 'a) option +(** [find_idx p x] returns [Some (i,x)] where [x] is the [i]-th element of [l], + and [p x] holds. Otherwise returns [None] *) + +val remove : ?eq:('a -> 'a -> bool) -> key:'a -> 'a t -> 'a t +(** [remove ~key l] removes every instance of [key] from [l]. Tailrec. + @param eq equality function + @since 0.11 *) + +val filter_map : f:('a -> 'b option) -> 'a t -> 'b t +(** Map and remove elements at the same time *) + +val sorted_merge : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list +(** Merges elements from both sorted list *) + +val sort_uniq : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list +(** Sort the list and remove duplicate elements *) + +val sorted_merge_uniq : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list +(** [sorted_merge_uniq l1 l2] merges the sorted lists [l1] and [l2] and + removes duplicates + @since 0.10 *) + +val is_sorted : ?cmp:('a -> 'a -> int) -> 'a list -> bool +(** [is_sorted l] returns [true] iff [l] is sorted (according to given order) + @param cmp the comparison function (default [Pervasives.compare]) + @since 0.17 *) + +val sorted_insert : ?cmp:('a -> 'a -> int) -> ?uniq:bool -> 'a -> 'a list -> 'a list +(** [sorted_insert x l] inserts [x] into [l] such that, if [l] was sorted, + then [sorted_insert x l] is sorted too. + @param uniq if true and [x] is already in sorted position in [l], then + [x] is not duplicated. Default [false] ([x] will be inserted in any case). + @since 0.17 *) + +(*$Q + Q.(pair small_int (list small_int)) (fun (x,l) -> \ + let l = List.sort Pervasives.compare l in \ + is_sorted (sorted_insert x l)) +*) + +val uniq_succ : ?eq:('a -> 'a -> bool) -> 'a list -> 'a list +(** [uniq_succ l] removes duplicate elements that occur one next to the other. + Examples: + [uniq_succ [1;2;1] = [1;2;1]] + [uniq_succ [1;1;2] = [1;2]] + @since 0.10 *) + +val group_succ : ?eq:('a -> 'a -> bool) -> 'a list -> 'a list list +(** [group_succ ~eq l] groups together consecutive elements that are equal + according to [eq] + @since 0.11 *) + +(** {2 Indices} *) + +val mapi : f:(int -> 'a -> 'b) -> 'a t -> 'b t + +val iteri : f:(int -> 'a -> unit) -> 'a t -> unit + +val foldi : f:('b -> int -> 'a -> 'b) -> init:'b -> 'a t -> 'b +(** Fold on list, with index *) + +val get_at_idx : int -> 'a t -> 'a option + +val get_at_idx_exn : int -> 'a t -> 'a +(** Get the i-th element, or + @raise Not_found if the index is invalid *) + +val set_at_idx : int -> 'a -> 'a t -> 'a t +(** Set i-th element (removes the old one), or does nothing if + index is too high *) + +val insert_at_idx : int -> 'a -> 'a t -> 'a t +(** Insert at i-th position, between the two existing elements. If the + index is too high, append at the end of the list *) + +val remove_at_idx : int -> 'a t -> 'a t +(** Remove element at given index. Does nothing if the index is + too high. *) + +(** {2 Set Operators} + + Those operations maintain the invariant that the list does not + contain duplicates (if it already satisfies it) *) + +val add_nodup : ?eq:('a -> 'a -> bool) -> 'a -> 'a t -> 'a t +(** [add_nodup x set] adds [x] to [set] if it was not already present. Linear time. + @since 0.11 *) + +val remove_one : ?eq:('a -> 'a -> bool) -> 'a -> 'a t -> 'a t +(** [remove_one x set] removes one occurrence of [x] from [set]. Linear time. + @since 0.11 *) + +val mem : ?eq:('a -> 'a -> bool) -> 'a -> 'a t -> bool +(** Membership to the list. Linear time *) + +val subset : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t -> bool +(** Test for inclusion *) + +val uniq : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t +(** Remove duplicates w.r.t the equality predicate. + Complexity is quadratic in the length of the list, but the order + of elements is preserved. If you wish for a faster de-duplication + but do not care about the order, use {!sort_uniq}*) + +val union : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t -> 'a t +(** List union. Complexity is product of length of inputs. *) + +val inter : ?eq:('a -> 'a -> bool) -> 'a t -> 'a t -> 'a t +(** List intersection. Complexity is product of length of inputs. *) + +(** {2 Other Constructors} *) + +val range_by : step:int -> int -> int -> int t +(** [range_by ~step i j] iterates on integers from [i] to [j] included, + where the difference between successive elements is [step]. + use a negative [step] for a decreasing list. + @raise Invalid_argument if [step=0] + @since 0.18 *) + +val range : int -> int -> int t +(** [range i j] iterates on integers from [i] to [j] included . It works + both for decreasing and increasing ranges *) + +val range' : int -> int -> int t +(** Same as {!range} but the second bound is excluded. + For instance [range' 0 5 = [0;1;2;3;4]] *) + +val (--) : int -> int -> int t +(** Infix alias for [range] *) + +val (--^) : int -> int -> int t +(** Infix alias for [range'] + @since 0.17 *) + +val replicate : int -> 'a -> 'a t +(** Replicate the given element [n] times *) + +val repeat : int -> 'a t -> 'a t +(** Concatenate the list with itself [n] times *) + +(** {2 Association Lists} *) + +module Assoc : sig + type ('a, 'b) t = ('a*'b) list + + val get : ?eq:('a->'a->bool) -> 'a -> ('a,'b) t -> 'b option + (** Find the element *) + + val get_exn : ?eq:('a->'a->bool) -> 'a -> ('a,'b) t -> 'b + (** Same as [get], but unsafe + @raise Not_found if the element is not present *) + + val set : ?eq:('a->'a->bool) -> 'a -> 'b -> ('a,'b) t -> ('a,'b) t + (** Add the binding into the list (erase it if already present) *) + + val mem : ?eq:('a->'a->bool) -> 'a -> ('a,_) t -> bool + (** [mem x l] returns [true] iff [x] is a key in [l] + @since 0.16 *) + + val update : + ?eq:('a->'a->bool) -> f:('b option -> 'b option) -> 'a -> ('a,'b) t -> ('a,'b) t + (** [update k ~f l] updates [l] on the key [k], by calling [f (get l k)] + and removing [k] if it returns [None], mapping [k] to [v'] if it + returns [Some v'] + @since 0.16 *) + + val remove : ?eq:('a->'a->bool) -> 'a -> ('a,'b) t -> ('a,'b) t + (** [remove x l] removes the first occurrence of [k] from [l]. + @since 0.17 *) +end + +(** {2 References on Lists} +@since 0.3.3 *) + +module Ref : sig + type 'a t = 'a list ref + + val push : 'a t -> 'a -> unit + + val pop : 'a t -> 'a option + + val pop_exn : 'a t -> 'a + (** Unsafe version of {!pop}. + @raise Failure if the list is empty *) + + val create : unit -> 'a t + (** Create a new list reference *) + + val clear : _ t -> unit + (** Remove all elements *) + + val lift : ('a list -> 'b) -> 'a t -> 'b + (** Apply a list function to the content *) + + val push_list : 'a t -> 'a list -> unit + (** Add elements of the list at the beginning of the list ref. Elements + at the end of the list will be at the beginning of the list ref *) +end + +(** {2 Monadic Operations} *) +module type MONAD = sig + type 'a t + val return : 'a -> 'a t + val (>>=) : 'a t -> ('a -> 'b t) -> 'b t +end + +module Traverse(M : MONAD) : sig + val sequence_m : 'a M.t t -> 'a t M.t + + val fold_m : f:('b -> 'a -> 'b M.t) -> init:'b -> 'a t -> 'b M.t + + val map_m : f:('a -> 'b M.t) -> 'a t -> 'b t M.t + + val map_m_par : f:('a -> 'b M.t) -> 'a t -> 'b t M.t + (** Same as {!map_m} but [map_m_par f (x::l)] evaluates [f x] and + [f l] "in parallel" before combining their result (for instance + in Lwt). *) +end + +(** {2 Conversions} *) + +type 'a sequence = ('a -> unit) -> unit +type 'a gen = unit -> 'a option +type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist] +type 'a printer = Format.formatter -> 'a -> unit +type 'a random_gen = Random.State.t -> 'a + +val random : 'a random_gen -> 'a t random_gen +val random_non_empty : 'a random_gen -> 'a t random_gen +val random_len : int -> 'a random_gen -> 'a t random_gen + +val random_choose : 'a t -> 'a random_gen +(** Randomly choose an element in the list. + @raise Not_found if the list is empty *) + +val random_sequence : 'a random_gen t -> 'a t random_gen + +val to_seq : 'a t -> 'a sequence +val of_seq : 'a sequence -> 'a t + +val to_gen : 'a t -> 'a gen +val of_gen : 'a gen -> 'a t + +val to_klist : 'a t -> 'a klist +val of_klist : 'a klist -> 'a t + +(** {2 Infix Operators} + It is convenient to {!open CCList.Infix} to access the infix operators + without cluttering the scope too much. + + @since 0.16 *) + +module Infix : sig + val (>|=) : 'a t -> ('a -> 'b) -> 'b t + val (@) : 'a t -> 'a t -> 'a t + val (<*>) : ('a -> 'b) t -> 'a t -> 'b t + val (<$>) : ('a -> 'b) -> 'a t -> 'b t + val (>>=) : 'a t -> ('a -> 'b t) -> 'b t + val (--) : int -> int -> int t + + val (--^) : int -> int -> int t + (** @since 0.17 *) +end + +(** {2 IO} *) + +val pp : ?start:string -> ?stop:string -> ?sep:string -> + 'a printer -> 'a t printer diff --git a/src/data/CCHashTrie.ml b/src/data/CCHashTrie.ml index b67d4f4c..44e3647d 100644 --- a/src/data/CCHashTrie.ml +++ b/src/data/CCHashTrie.ml @@ -604,7 +604,7 @@ module Make(Key : KEY) aux acc t (*$T - let l = CCList.(1 -- 10 |> map ~f:(fun x->x,x)) in \ + let l = CCList.(1 -- 10 |> map (fun x->x,x)) in \ M.of_list l \ |> M.fold ~f:(fun acc x y -> (x,y)::acc) ~x:[] \ |> List.sort Pervasives.compare = l @@ -720,7 +720,7 @@ module Make(Key : KEY) end (*$R - let m = M.of_list CCList.( (501 -- 1000) @ (500 -- 1) |> map ~f:(fun i->i,i)) in + let m = M.of_list CCList.( (501 -- 1000) @ (500 -- 1) |> map (fun i->i,i)) in assert_equal ~printer:CCInt.to_string 1000 (M.cardinal m); assert_bool "check all get" (Sequence.for_all (fun i -> i = M.get_exn i m) Sequence.(1 -- 1000)); diff --git a/src/data/CCWBTree.ml b/src/data/CCWBTree.ml index acceb506..bdff0d45 100644 --- a/src/data/CCWBTree.ml +++ b/src/data/CCWBTree.ml @@ -361,7 +361,7 @@ module MakeFull(K : KEY) : S with type key = K.t = struct with Not_found -> None (*$T - let m = CCList.(0 -- 1000 |> map ~f:(fun i->i,i) |> M.of_list) in \ + let m = CCList.(0 -- 1000 |> map (fun i->i,i) |> M.of_list) in \ List.for_all (fun i -> M.nth_exn i m = (i,i)) CCList.(0--1000) *)