From 58277c77bbe0c0c1b713d01df1b06483829a27f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Wos=CC=81?= Date: Wed, 6 Dec 2017 13:05:20 +0900 Subject: [PATCH 1/2] Automatically add labeled interface to CCList and CCArray --- src/core/CCArrayLabels.ml | 617 +------------------ src/core/CCListLabels.ml | 1184 +------------------------------------ 2 files changed, 2 insertions(+), 1799 deletions(-) diff --git a/src/core/CCArrayLabels.ml b/src/core/CCArrayLabels.ml index f6573cb8..fdf51544 100644 --- a/src/core/CCArrayLabels.ml +++ b/src/core/CCArrayLabels.ml @@ -1,619 +1,4 @@ (* 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 - -(*$T - let st = Random.State.make [||] in let a = 0--10000 in \ - let b = Array.copy a in shuffle_with st a; a <> b -*) - -(** {2 Arrays} *) - -include ArrayLabels - -type 'a t = 'a array - -let empty = [| |] - -let map = Array.map - -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)) - -let length = Array.length - -let get = Array.get - -let get_safe a i = - if i>=0 && i acc - | `Continue -> fold_while_i f acc (i+1) - else acc - in fold_while_i f acc 0 - -(*$T - 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 = Array.iter - -let iteri = Array.iteri - -let blit = Array.blit - -let reverse_in_place a = - let len = Array.length a in - if len>0 then ( - for k = 0 to (len-1)/2 do - let t = a.(k) in - a.(k) <- a.(len-1-k); - a.(len-1-k) <- t; - done - ) - -(*$T - reverse_in_place [| |]; true - reverse_in_place [| 1 |]; true - let a = [| 1; 2; 3; 4; 5 |] in \ - reverse_in_place a; \ - a = [| 5;4;3;2;1 |] - let a = [| 1; 2; 3; 4; 5; 6 |] in \ - reverse_in_place a; \ - a = [| 6;5;4;3;2;1 |] -*) - -let sorted cmp a = - let b = Array.copy a in - Array.sort cmp b; - b - -(*$= & ~cmp:(=) ~printer:Q.Print.(array int) - [||] (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 Pervasives.compare 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 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 String.compare a in \ - sorted String.compare a = Array.map (Array.get a) b) -*) - -let sort_ranking cmp a = - let cmp_int : int -> int -> int = Pervasives.compare in - sort_indices cmp_int (sort_indices cmp a) - -(*$= & ~cmp:(=) ~printer:Q.Print.(array int) - [||] (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 String.compare a in \ - let a_sorted = sorted String.compare a in \ - a = Array.map (Array.get a_sorted) b) -*) - -let rev a = - let b = Array.copy a in - reverse_in_place b; - b - -(*$Q - Q.(array small_int) (fun a -> rev (rev a) = a) -*) - -(*$T - rev [| 1; 2; 3 |] = [| 3; 2; 1 |] - rev [| 1; 2; |] = [| 2; 1 |] - rev [| |] = [| |] -*) - -let rec find_aux f a i = - if i = Array.length a then None - else match f i a.(i) with - | Some _ as res -> res - | None -> find_aux f a (i+1) - -let find f a = - find_aux (fun _ -> f ) a 0 - -let findi f a = - find_aux f 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 rec aux acc i = - if i = Array.length a - then ( - let a' = Array.of_list acc in - reverse_in_place a'; - a' - ) else match f a.(i) with - | None -> aux acc (i+1) - | Some x -> aux (x::acc) (i+1) - in aux [] 0 - -(*$T - filter_map (fun x -> if x mod 2 = 0 then Some (string_of_int x) else None) \ - [| 1; 2; 3; 4 |] = [| "2"; "4" |] - filter_map (fun x -> if x mod 2 = 0 then Some (string_of_int x) else None) \ - [| 1; 2; 3; 4; 5; 6 |] \ - = [| "2"; "4"; "6" |] -*) - -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 = - if i = Array.length a - then acc - else - __rev_append_list a (a.(i) :: acc) (i+1) - -let flat_map f a = - let rec aux acc i = - if i = Array.length a - then ( - let a' = Array.of_list acc in - reverse_in_place a'; - a' - ) - else - let a' = f a.(i) in - aux (__rev_append_list a' acc 0) (i+1) - in aux [] 0 - -(*$T - let a = [| 1; 3; 5 |] in \ - let a' = flat_map (fun x -> [| x; x+1 |]) a in \ - a' = [| 1; 2; 3; 4; 5; 6 |] -*) - -let rec _lookup_rec ~cmp k a i j = - if i>j then raise Not_found - else if i=j - then if cmp k a.(i) = 0 - then i - else raise Not_found - else - let middle = (j+i)/2 in - match cmp k a.(middle) with - | 0 -> middle - | n when n<0 -> _lookup_rec ~cmp k a i (middle-1) - | _ -> _lookup_rec ~cmp k a (middle+1) j - -let _lookup_exn ~cmp k a i j = - if i>j then raise Not_found; - match cmp k a.(i) with - | 0 -> i - | n when n<0 -> raise Not_found (* too low *) - | _ when i=j -> raise Not_found (* too high *) - | _ -> - match cmp k a.(j) with - | 0 -> 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) k a = - _lookup_exn ~cmp k 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 - lookup 2 [|0;1;2;3;4;5|] = Some 2 - lookup 4 [|0;1;2;3;4;5|] = Some 4 - lookup 0 [|1;2;3;4;5|] = None - lookup 6 [|1;2;3;4;5|] = None - lookup 3 [| |] = None - lookup 1 [| 1 |] = Some 0 - lookup 2 [| 1 |] = None -*) - -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 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) k, cmp a.(n-1) k with - | c, _ when c>0 -> `All_bigger - | _, c when c<0 -> `All_lower - | _ -> aux 0 (n-1) - -(*$T bsearch - bsearch 3 [|1; 2; 2; 3; 4; 10|] = `At 3 - bsearch 5 [|1; 2; 2; 3; 4; 10|] = `Just_after 4 - bsearch 1 [|1; 2; 5; 5; 11; 12|] = `At 0 - bsearch 12 [|1; 2; 5; 5; 11; 12|] = `At 5 - bsearch 10 [|1; 2; 2; 3; 4; 9|] = `All_lower - bsearch 0 [|1; 2; 2; 3; 4; 9|] = `All_bigger - bsearch 3 [| |] = `Empty -*) - -let (>>=) a f = flat_map f a - -let (>>|) a f = map f a - -let (>|=) a f = map f a - -let for_all p a = - let rec aux i = - i = Array.length a || (p a.(i) && aux (i+1)) - in - aux 0 - -let exists p a = - let rec aux i = - 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 p a b = - Array.length a = Array.length b - && - _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 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 - f (Array.get a (i+o)) (Array.get b (j+o)) - done - -let _fold2 f acc a b i j ~len = - let rec aux acc o = - if o=len then acc - else - let acc = f acc (Array.get a (i+o)) (Array.get b (j+o)) in - aux acc (o+1) - in - aux acc 0 - -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 acc a b = - if length a <> length b then invalid_arg "fold2"; - _fold2 f acc a b 0 0 ~len:(Array.length a) - -let (--) i j = - if i<=j - then - Array.init (j-i+1) (fun k -> i+k) - else - Array.init (i-j+1) (fun k -> i-k) - -(*$T - (1 -- 4) |> Array.to_list = [1;2;3;4] - (4 -- 1) |> Array.to_list = [4;3;2;1] - (0 -- 0) |> Array.to_list = [0] -*) - -(*$Q - Q.(pair small_int small_int) (fun (a,b) -> \ - (a -- b) |> Array.to_list = CCList.(a -- b)) -*) - -let (--^) i j = - if i=j then [| |] - else if i>j - then Array.init (i-j) (fun k -> i-k) - else Array.init (j-i) (fun k -> i+k) - -(*$Q - Q.(pair small_int small_int) (fun (a,b) -> \ - (a --^ b) |> Array.to_list = CCList.(a --^ b)) -*) - -(** all the elements of a, but the i-th, into a list *) -let except_idx a i = - foldi - (fun acc j elt -> if i = j then acc else elt::acc) - [] a - -let equal eq a b = - let rec aux i = - if i = Array.length a then true - else eq a.(i) b.(i) && aux (i+1) - in - Array.length a = Array.length b - && - aux 0 - -(*$Q - Q.(pair (array small_int)(array small_int)) (fun (a,b) -> \ - equal (=) a b = equal (=) b a) -*) - -(*$T - equal (=) [|1|] [|1|] -*) - -let compare cmp a b = - let rec aux i = - if i = Array.length a - then if i = Array.length b then 0 else -1 - else if i = Array.length b - then 1 - else - let c = cmp a.(i) b.(i) in - if c = 0 then aux (i+1) else c - in - aux 0 - -(*$T - compare CCOrd.compare [| 1; 2; 3 |] [| 1; 2; 3 |] = 0 - compare CCOrd.compare [| 1; 2; 3 |] [| 2; 2; 3 |] < 0 - compare CCOrd.compare [| 1; 2; |] [| 1; 2; 3 |] < 0 - compare CCOrd.compare [| 1; 2; 3 |] [| 1; 2; |] > 0 -*) - -(* shuffle a[i...j[ using the given int random generator - See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle *) -let _shuffle _rand_int a i j = - for k = j-1 downto i+1 do - let l = _rand_int (k+1) in - let tmp = a.(l) in - a.(l) <- a.(k); - a.(k) <- tmp; - done - -let shuffle a = - _shuffle Random.int a 0 (Array.length a) - -let shuffle_with st a = - _shuffle (Random.State.int st) a 0 (Array.length a) - -let rec _to_klist a i j () = - if i=j then `Nil else `Cons (a.(i), _to_klist a (i+1) j) - -let random_choose a st = - let n = Array.length a in - if n = 0 then raise Not_found; - a.(Random.State.int st n) - -let random_len n g st = - Array.init n (fun _ -> g st) - -let random g st = - let n = Random.State.int st 1_000 in - random_len n g st - -let random_non_empty g st = - let n = 1 + Random.State.int st 1_000 in - random_len n g st - -let pp ?(sep=", ") pp_item out a = - for k = 0 to Array.length a-1 do - if k > 0 then (Format.pp_print_string out sep; Format.pp_print_cut out ()); - pp_item out a.(k) - done - -let pp_i ?(sep=", ") pp_item out a = - for k = 0 to Array.length a - 1 do - if k > 0 then (Format.pp_print_string out sep; Format.pp_print_cut out ()); - pp_item k out a.(k) - done - -let to_seq a k = iter k a - -let to_gen a = - let k = ref 0 in - fun () -> - if !k < Array.length a - then ( - let x = a.(!k) in - incr k; - Some x - ) else None - -let to_klist a = _to_klist a 0 (Array.length a) - -(** {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 - -(* Dual Pivot Quicksort (Yaroslavskiy) - from "average case analysis of Java 7's Dual Pivot Quicksort" *) -module SortGeneric(A : MONO_ARRAY) = struct - module Rand = Random.State - - let seed_ = [|123456|] - - type state = { - mutable l: int; (* left pointer *) - mutable g: int; (* right pointer *) - mutable k: int; - } - - let rand_idx_ rand i j = i + Rand.int rand (j-i) - - let swap_ a i j = - if i=j then () - else ( - let tmp = A.get a i in - A.set a i (A.get a j); - A.set a j tmp - ) - - let sort ~cmp a = - let rec insert_ a i k = - if k 0 then ( - swap_ a k (k+1); - insert_ a i (k-1) - ) - in - (* recursive part of insertion sort *) - let rec sort_insertion_rec a i j k = - if k 1 then sort_insertion_rec a i j (i+1) - in - let rand = Rand.make seed_ in - (* sort slice. - There is a chance that the two pivots are equal, but it's unlikely. *) - let rec sort_slice_ ~st a i j = - if j-i>10 then ( - st.l <- i; - st.g <- j-1; - st.k <- i; - (* choose pivots *) - let p = A.get a (rand_idx_ rand i j) in - let q = A.get a (rand_idx_ rand i j) in - (* invariant: st.p <= st.q, swap them otherwise *) - let p, q = if cmp p q > 0 then q, p else p, q in - while st.k <= st.g do - let cur = A.get a st.k in - if cmp cur p < 0 then ( - (* insert in leftmost band *) - if st.k <> st.l then swap_ a st.k st.l; - st.l <- st.l + 1 - ) else if cmp cur q > 0 then ( - (* insert in rightmost band *) - while st.k < st.g && cmp (A.get a st.g) q > 0 do - st.g <- st.g - 1 - done; - swap_ a st.k st.g; - st.g <- st.g - 1; - (* the element swapped from the right might be in the first situation. - that is, < p (we know it's <= q already) *) - if cmp (A.get a st.k) p < 0 then ( - if st.k <> st.l then swap_ a st.k st.l; - st.l <- st.l + 1 - ) - ); - st.k <- st.k + 1 - done; - (* save values before recursing *) - let l = st.l and g = st.g and sort_middle = cmp p q < 0 in - sort_slice_ ~st a i l; - if sort_middle then sort_slice_ ~st a l (g+1); - sort_slice_ ~st a (g+1) j; - ) else sort_insertion a i j - in - if A.length a > 0 then ( - let st = { l=0; g=A.length a; k=0; } in - sort_slice_ ~st a 0 (A.length a) - ) -end - - -let sort_generic (type arr)(type elt) - (module A : MONO_ARRAY with type t = arr and type elt = elt) - ?(cmp=Pervasives.compare) a - = - let module S = SortGeneric(A) in - S.sort ~cmp a - -(*$inject - module IA = struct - type elt = int - type t = int array - include Array - end - - let gen_arr = Q.Gen.(array_size (1--100) small_int) - let arr_arbitrary = Q.make - ~print:Q.Print.(array int) - ~small:Array.length - ~shrink:Q.Shrink.(array ?shrink:None) - gen_arr -*) - -(*$Q & ~count:300 - arr_arbitrary (fun a -> \ - let a1 = Array.copy a and a2 = Array.copy a in \ - Array.sort CCInt.compare a1; sort_generic ~cmp:CCInt.compare (module IA) a2; \ - a1 = a2 ) -*) +include CCArray diff --git a/src/core/CCListLabels.ml b/src/core/CCListLabels.ml index 61df2913..e2f676b6 100644 --- a/src/core/CCListLabels.ml +++ b/src/core/CCListLabels.ml @@ -1,1186 +1,4 @@ (* This file is free software, part of containers. See file "license" for more details. *) -(** {1 complements to list} *) - -(*$inject - let lsort l = List.sort Pervasives.compare l -*) - -include ListLabels - -type 'a t = 'a list - -let empty = [] - -let is_empty = function - | [] -> true - | _::_ -> false - -(* max depth for direct recursion *) -let direct_depth_default_ = 1000 - -let map f l = - let rec direct f i l = match l with - | [] -> [] - | [x] -> [f x] - | [x1;x2] -> let y1 = f x1 in [y1; f x2] - | [x1;x2;x3] -> let y1 = f x1 in let y2 = f x2 in [y1; y2; f x3] - | _ when i=0 -> List.rev (List.rev_map f l) - | x1::x2::x3::x4::l' -> - let y1 = f x1 in - let y2 = f x2 in - let y3 = f x3 in - let y4 = f x4 in - y1 :: y2 :: y3 :: y4 :: direct f (i-1) l' - in - direct f direct_depth_default_ l - -(*$Q - (Q.list Q.small_int) (fun l -> \ - let f x = x+1 in \ - List.rev (List.rev_map f l) = map f l) -*) - -let (>|=) l f = map f l - -let direct_depth_append_ = 10_000 - -let cons x l = x::l - -let append l1 l2 = - let rec direct i l1 l2 = match l1 with - | [] -> l2 - | _ when i=0 -> safe l1 l2 - | x::l1' -> x :: direct (i-1) l1' l2 - and safe l1 l2 = - List.rev_append (List.rev l1) l2 - in - match l1 with - | [] -> l2 - | [x] -> x::l2 - | [x;y] -> x::y::l2 - | _ -> direct direct_depth_append_ l1 l2 - -let (@) = append - -(*$T - [1;2;3] @ [4;5;6] = [1;2;3;4;5;6] - (1-- 10_000) @ (10_001 -- 20_000) = 1 -- 20_000 -*) - -let cons_maybe o l = match o with - | Some x -> x :: l - | None -> l - -(*$T - cons_maybe (Some 1) [2;3] = [1;2;3] - cons_maybe None [2;3] = [2;3] -*) - -let direct_depth_filter_ = 10_000 - -let filter p l = - let rec direct i p l = match l with - | [] -> [] - | _ when i=0 -> safe p l [] - | x::l' when not (p x) -> direct i p l' - | x::l' -> x :: direct (i-1) p l' - and safe p l acc = match l with - | [] -> List.rev acc - | x::l' when not (p x) -> safe p l' acc - | x::l' -> safe p l' (x::acc) - in - direct direct_depth_filter_ p l - -(*$= & ~printer:CCInt.to_string - 500 (filter (fun x->x mod 2 = 0) (1 -- 1000) |> List.length) - 50_000 (filter (fun x->x mod 2 = 0) (1 -- 100_000) |> List.length) - 500_000 (filter (fun x->x mod 2 = 0) (1 -- 1_000_000) |> List.length) -*) - -let fold_right f l acc = - let rec direct i f l acc = match l with - | [] -> acc - | _ when i=0 -> safe f (List.rev l) acc - | x::l' -> - let acc = direct (i-1) f l' acc in - f x acc - and safe f l acc = match l with - | [] -> acc - | x::l' -> - let acc = f x acc in - safe f l' acc - in - direct direct_depth_default_ f l acc - -(*$T - fold_right (+) (1 -- 1_000_000) 0 = \ - List.fold_left (+) 0 (1 -- 1_000_000) -*) - -(*$Q - (Q.list Q.small_int) (fun l -> \ - l = fold_right (fun x y->x::y) l []) -*) - -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 acc l - -(*$T - fold_while (fun acc b -> if b then acc+1, `Continue else acc, `Stop) 0 [true;true;false;true] = 2 -*) - -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 acc [] l - -(*$= - (6, ["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 (fun acc x -> x::acc, x) [] l = (List.rev l, l)) -*) - -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 - | [], _ - | _, [] -> invalid_arg "fold_map2" - | x1 :: l1', x2 :: l2' -> - let acc, y = f acc x1 x2 in - aux f acc (y :: map_acc) l1' l2' - in - aux f acc [] l1 l2 - -(*$= - (310, ["1 10"; "2 0"; "3 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 (fun _ _ _ -> assert false) 42 [] [1]); false \ - with Invalid_argument _ -> true) -*) - -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 acc [] l - -(*$= & ~printer:Q.Print.(pair int (list int)) - (List.fold_left (+) 0 (1--10), [2;4;6;8;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 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 acc [] l - -(*$= - (6, ["1"; "a1"; "2"; "a2"; "3"; "a3"]) \ - (let pf = Printf.sprintf in \ - 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 (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 rec init_rec acc i f = - if i=0 then f i :: acc - else init_rec (f i :: acc) (i-1) f - in - if len<0 then invalid_arg "init" - else if len=0 then [] - else init_rec [] (len-1) f - -(*$T - 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 - | [], [] -> 0 - | _, [] -> 1 - | [], _ -> -1 - | x1::l1', x2::l2' -> - let c = f x1 x2 in - if c <> 0 then c else compare f l1' l2' - -let rec equal f l1 l2 = match l1, l2 with - | [], [] -> true - | [], _ | _, [] -> false - | x1::l1', x2::l2' -> f x1 x2 && equal f l1' l2' - -(*$T - equal CCInt.equal (1--1_000_000) (1--1_000_000) -*) - -let flat_map f l = - let rec aux f l kont = match l with - | [] -> kont [] - | x::l' -> - let y = f x in - let kont' tail = match y with - | [] -> kont tail - | [x] -> kont (x :: tail) - | [x;y] -> kont (x::y::tail) - | l -> kont (append l tail) - in - aux f l' kont' - in - aux f l (fun l->l) - -(*$T - flat_map (fun x -> [x+1; x*2]) [10;100] = [11;20;101;200] - List.length (flat_map (fun x->[x]) (1--300_000)) = 300_000 -*) - -let flatten l = fold_right append l [] - -(*$T - flatten [[1]; [2;3;4]; []; []; [5;6]] = 1--6 - flatten (init 300_001 (fun x->[x])) = 0--300_000 -*) - -let product f l1 l2 = - flat_map (fun x -> map (fun y -> f x y) l2) l1 - -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 - ) acc l1 - -let diagonal l = - let rec gen acc l = match l with - | [] -> acc - | x::l' -> - let acc = List.fold_left (fun acc y -> (x,y) :: acc) acc l' in - gen acc l' - in - gen [] l - -(*$T - diagonal [] = [] - diagonal [1] = [] - diagonal [1;2] = [1,2] - diagonal [1;2;3] |> List.sort Pervasives.compare = [1, 2; 1, 3; 2, 3] -*) - -let partition_map f l = - let rec iter f l1 l2 l = match l with - | [] -> List.rev l1, List.rev l2 - | x :: tl -> - match f x with - | `Left y -> iter f (y :: l1) l2 tl - | `Right y -> iter f l1 (y :: l2) tl - | `Drop -> iter f l1 l2 tl - in - iter f [] [] l - -(*$R - let l1, l2 = - partition_map (function - | n when n = 0 -> `Drop - | n when n mod 2 = 0 -> `Left n - | n -> `Right n - ) [0;1;2;3;4] - in - assert_equal [2;4] l1; - assert_equal [1;3] l2 -*) - -let return x = [x] - -let (>>=) l f = flat_map f l - -let (<$>) = map - -let pure = return - -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 - | [], _ -> List.rev_append acc l2 - | _, [] -> List.rev_append acc l1 - | x1::l1', x2::l2' -> - let c = cmp x1 x2 in - if c < 0 then recurse cmp (x1::acc) l1' l2 - else if c > 0 then recurse cmp (x2::acc) l1 l2' - else recurse cmp (x1::x2::acc) l1' l2' - in - recurse cmp [] l1 l2 - -(*$T - List.sort Pervasives.compare ([(( * )2); ((+)1)] <*> [10;100]) \ - = [11; 20; 101; 200] - sorted_merge [1;1;2] [1;2;3] = [1;1;1;2;2;3] -*) - -(*$Q - Q.(pair (list int) (list int)) (fun (l1,l2) -> \ - List.length (sorted_merge l1 l2) = List.length l1 + List.length l2) -*) - -let sort_uniq (type elt) ?(cmp=Pervasives.compare) l = - let module S = Set.Make(struct - type t = elt - let compare = cmp - end) in - let set = fold_right S.add l S.empty in - S.elements set - -(*$T - sort_uniq [1;2;5;3;6;1;4;2;3] = [1;2;3;4;5;6] - sort_uniq [] = [] - sort_uniq [10;10;10;10;1;10] = [1;10] -*) - -let is_sorted ?(cmp=Pervasives.compare) l = - let rec aux cmp = function - | [] | [_] -> true - | x :: ((y :: _) as tail) -> cmp x y <= 0 && aux cmp tail - in - aux cmp l - -(*$Q - Q.(list small_int) (fun l -> \ - is_sorted (List.sort Pervasives.compare l)) -*) - -let sorted_insert ?(cmp=Pervasives.compare) ?(uniq=false) x l = - let rec aux cmp uniq x left l = match l with - | [] -> List.rev_append left [x] - | y :: tail -> - match cmp x y with - | 0 -> - let l' = if uniq then l else x :: l in - List.rev_append left l' - | n when n<0 -> List.rev_append left (x :: l) - | _ -> aux cmp uniq x (y::left) tail - in - aux cmp uniq x [] l - -(*$Q - Q.(pair small_int (list small_int)) (fun (x,l) -> \ - let l = List.sort Pervasives.compare l in \ - is_sorted (sorted_insert ~uniq:true x l)) - Q.(pair small_int (list small_int)) (fun (x,l) -> \ - let l = List.sort Pervasives.compare l in \ - is_sorted (sorted_insert ~uniq:false x l)) - Q.(pair small_int (list small_int)) (fun (x,l) -> \ - let l = List.sort Pervasives.compare l in \ - let l' = sorted_insert ~uniq:false x l in \ - List.length l' = List.length l + 1) - Q.(pair small_int (list small_int)) (fun (x,l) -> \ - let l = List.sort Pervasives.compare l in \ - List.mem x (sorted_insert x l)) -*) - -let uniq_succ ?(eq=(=)) l = - let rec f acc l = match l with - | [] -> List.rev acc - | [x] -> List.rev (x::acc) - | x :: ((y :: _) as tail) when eq x y -> f acc tail - | x :: tail -> f (x::acc) tail - in - f [] l - -(*$T - uniq_succ [1;1;2;3;1;6;6;4;6;1] = [1;2;3;1;6;4;6;1] -*) - -let group_succ ?(eq=(=)) l = - let rec f ~eq acc cur l = match cur, l with - | [], [] -> List.rev acc - | _::_, [] -> List.rev (List.rev cur :: acc) - | [], x::tl -> f ~eq acc [x] tl - | (y :: _), x :: tl when eq x y -> f ~eq acc (x::cur) tl - | _, x :: tl -> f ~eq (List.rev cur :: acc) [x] tl - in - f ~eq [] [] l - -(*$T - group_succ [1;2;3;1;1;2;4] = [[1]; [2]; [3]; [1;1]; [2]; [4]] - group_succ [] = [] - group_succ [1;1;1] = [[1;1;1]] - group_succ [1;2;2;2] = [[1]; [2;2;2]] - group_succ ~eq:(fun (x,_)(y,_)-> x=y) [1, 1; 1, 2; 1, 3; 2, 0] \ - = [[1, 1; 1, 2; 1, 3]; [2, 0]] -*) - -let sorted_merge_uniq ?(cmp=Pervasives.compare) l1 l2 = - let push ~cmp acc x = match acc with - | [] -> [x] - | y :: _ when cmp x y > 0 -> x :: acc - | _ -> acc (* duplicate, do not yield *) - in - let rec recurse ~cmp acc l1 l2 = match l1,l2 with - | [], l - | l, [] -> - let acc = List.fold_left (push ~cmp) acc l in - List.rev acc - | x1::l1', x2::l2' -> - let c = cmp x1 x2 in - if c < 0 then recurse ~cmp (push ~cmp acc x1) l1' l2 - else if c > 0 then recurse ~cmp (push ~cmp acc x2) l1 l2' - else recurse ~cmp acc l1 l2' (* drop one of the [x] *) - in - recurse ~cmp [] l1 l2 - -(*$T - sorted_merge_uniq [1; 1; 2; 3; 5; 8] [1; 2; 3; 4; 6; 8; 9; 9] = [1;2;3;4;5;6;8;9] -*) - -(*$Q - Q.(list int) (fun l -> \ - let l = List.sort Pervasives.compare l in \ - sorted_merge_uniq l [] = uniq_succ l) - Q.(list int) (fun l -> \ - let l = List.sort Pervasives.compare l in \ - sorted_merge_uniq [] l = uniq_succ l) - Q.(pair (list int) (list int)) (fun (l1, l2) -> \ - let l1 = List.sort Pervasives.compare l1 \ - and l2 = List.sort Pervasives.compare l2 in \ - let l3 = sorted_merge_uniq l1 l2 in \ - uniq_succ l3 = l3) -*) - -let take n l = - let rec direct i n l = match l with - | [] -> [] - | _ when i=0 -> safe n [] l - | x::l' -> - if n > 0 - then x :: direct (i-1) (n-1) l' - else [] - and safe n acc l = match l with - | [] -> List.rev acc - | _ when n=0 -> List.rev acc - | x::l' -> safe (n-1) (x::acc) l' - in - direct direct_depth_default_ n l - -(*$T - take 2 [1;2;3;4;5] = [1;2] - take 10_000 (range 0 100_000) |> List.length = 10_000 - take 10_000 (range 0 2_000) = range 0 2_000 - take 300_000 (1 -- 400_000) = 1 -- 300_000 -*) - -(*$Q - (Q.pair (Q.list Q.small_int) Q.int) (fun (l,i) -> \ - let i = abs i in \ - let l1 = take i l in \ - List.length l1 <= i && ((List.length l1 = i) = (List.length l >= i))) -*) - -let rec drop n l = match l with - | [] -> [] - | _ when n=0 -> l - | _::l' -> drop (n-1) l' - -let hd_tl = function - | [] -> failwith "hd_tl" - | x :: l -> x, l - -(*$T - try ignore (hd_tl []); false with Failure _ -> true - hd_tl [1;2;3] = (1, [2;3]) -*) - -let take_drop n l = take n l, drop n l - -(*$Q - (Q.pair (Q.list Q.small_int) Q.int) (fun (l,i) -> \ - let i = abs i in \ - let l1, l2 = take_drop i l in \ - l1 @ l2 = l ) -*) - -let sublists_of_len ?(last=fun _ -> None) ?offset n l = - if n < 1 then invalid_arg "sublists_of_len: n must be > 0"; - let offset = match offset with - | None -> n - | Some o when o < 1 -> invalid_arg "sublists_of_len: offset must be > 0" - | Some o -> o - in - (* add sub-lists of [l] to [acc] *) - let rec aux acc l = - let group = take n l in - if group=[] then acc (* this was the last group, we are done *) - else if List.length group < n (* last group, with missing elements *) - then match last group with - | None -> acc - | Some group' -> group' :: acc - else ( - let l' = drop offset l in - aux (group :: acc) l' (* continue *) - ) - in - List.rev (aux [] l) - -(*$= sublists_of_len as subs & ~printer:Q.Print.(list (list int)) - [[1;2;3]] (subs 3 [1;2;3;4]) - [[1;2]; [3;4]; [5;6]] (subs 2 [1;2;3;4;5;6]) - [] (subs 3 [1;2]) - [[1;2];[3;4]] (subs 2 ~offset:2 [1;2;3;4]) - [[1;2];[2;3]] (subs 2 ~offset:1 [1;2;3]) - [[1;2];[4;5]] (subs 2 ~offset:3 [1;2;3;4;5;6]) - [[1;2;3];[4]] (subs 3 ~last:CCOpt.return [1;2;3;4]) - [[1;2]; [3;4]] (subs 2 [1;2;3;4;5]) -*) - -let take_while p l = - let rec direct i p l = match l with - | [] -> [] - | _ when i=0 -> safe p [] l - | x :: l' -> - if p x then x :: direct (i-1) p l' else [] - and safe p acc l = match l with - | [] -> List.rev acc - | x :: l' -> - if p x then safe p (x::acc) l' else List.rev acc - in - direct direct_depth_default_ p l - -(*$T - 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 - Q.(pair (fun1 small_int bool) (list small_int)) (fun (f,l) -> \ - let l1 = take_while f l in \ - List.for_all f l1) -*) - -let rec drop_while p l = match l with - | [] -> [] - | 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) -> \ - take_while f l @ drop_while f l = l) -*) - -let last n l = - let len = List.length l in - if len < n then l else drop (len-n) l - -let head_opt = function - | [] -> None - | x::_ -> Some x - -let rec last_opt = function - | [] -> None - | [x] -> Some x - | _ :: tail -> last_opt tail - -(*$= & ~printer:Q.Print.(option int) - (Some 1) (head_opt [1;2;3]) - (Some 1) (head_opt [1]) - None (head_opt []) - (Some 3) (last_opt [1;2;3]) - (Some 1) (last_opt [1]) - None (last_opt []) -*) - -let rec find_pred p l = match l with - | [] -> None - | x :: _ when p x -> Some x - | _ :: tl -> find_pred p tl - -let find_pred_exn p l = match find_pred p l with - | None -> raise Not_found - | Some x -> x - -(*$T - 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 rec aux f i = function - | [] -> None - | x::l' -> - match f i x with - | Some _ as res -> res - | None -> aux f (i+1) l' - in aux f 0 l - -let find_map f l = find_mapi (fun _ -> f) l - -let find_idx p l = find_mapi (fun i x -> if p x then Some (i, x) else None) l - -(*$T - find_map (fun x -> if x=3 then Some "a" else None) [1;2;3;4] = Some "a" - find_map (fun x -> if x=3 then Some "a" else None) [1;2;4;5] = None -*) - -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 x [] l - -(*$T - 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 rec recurse acc l = match l with - | [] -> List.rev acc - | x::l' -> - let acc' = match f x with | None -> acc | Some y -> y::acc in - recurse acc' l' - in recurse [] l - -(*$= - ["2"; "4"] \ - (filter_map (fun x -> if x mod 2 = 0 then Some (string_of_int x) else None) \ - [1;2;3;4;5]) - [ "2"; "4"; "6" ] \ - (filter_map (fun x -> if x mod 2 = 0 then Some (string_of_int x) else None) \ - [ 1; 2; 3; 4; 5; 6 ]) -*) - -let mem ?(eq=(=)) x l = - let rec search eq x l = match l with - | [] -> false - | y::l' -> eq x y || search eq x l' - in search eq x l - -let add_nodup ?(eq=(=)) x l = - if mem ~eq x l then l else x::l - -let remove_one ?(eq=(=)) x l = - let rec remove_one ~eq x acc l = match l with - | [] -> assert false - | y :: tl when eq x y -> List.rev_append acc tl - | y :: tl -> remove_one ~eq x (y::acc) tl - in - if mem ~eq x l then remove_one ~eq x [] l else l - -(*$Q - Q.(pair int (list int)) (fun (x,l) -> \ - remove_one x (add_nodup x l) = l) - Q.(pair int (list int)) (fun (x,l) -> \ - mem x l || List.length (add_nodup x l) = List.length l + 1) - Q.(pair int (list int)) (fun (x,l) -> \ - not (mem x l) || List.length (remove_one x l) = List.length l - 1) -*) - -let subset ?(eq=(=)) l1 l2 = - List.for_all - (fun t -> mem ~eq t l2) - l1 - -let uniq ?(eq=(=)) l = - let rec uniq eq acc l = match l with - | [] -> List.rev acc - | x::xs when List.exists (eq x) xs -> uniq eq acc xs - | x::xs -> uniq eq (x::acc) xs - in uniq eq [] l - -(*$T - uniq [1;1;2;2;3;4;4;2;4;1;5] |> List.sort Pervasives.compare = [1;2;3;4;5] -*) - -let union ?(eq=(=)) l1 l2 = - let rec union eq acc l1 l2 = match l1 with - | [] -> List.rev_append acc l2 - | x::xs when mem ~eq x l2 -> union eq acc xs l2 - | x::xs -> union eq (x::acc) xs l2 - in union eq [] l1 l2 - -(*$T - union [1;2;4] [2;3;4;5] = [1;2;3;4;5] -*) - -let inter ?(eq=(=)) l1 l2 = - let rec inter eq acc l1 l2 = match l1 with - | [] -> List.rev acc - | x::xs when mem ~eq x l2 -> inter eq (x::acc) xs l2 - | _::xs -> inter eq acc xs l2 - in inter eq [] l1 l2 - -(*$T - inter [1;2;4] [2;3;4;5] = [2;4] -*) - -let mapi f l = - let r = ref 0 in - map - (fun x -> - let y = f !r x in - incr r; y - ) l - -(*$T - mapi (fun i x -> i*x) [10;10;10] = [0;10;20] -*) - -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 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 acc 0 l - -let rec get_at_idx_exn i l = match l with - | [] -> raise Not_found - | x::_ when i=0 -> x - | _::l' -> get_at_idx_exn (i-1) l' - -let get_at_idx i l = - try Some (get_at_idx_exn i l) - with Not_found -> None - -(*$T - get_at_idx 0 (range 0 10) = Some 0 - get_at_idx 5 (range 0 10) = Some 5 - get_at_idx 11 (range 0 10) = None - get_at_idx 0 [] = None -*) - -let set_at_idx i x l0 = - let rec aux l acc i = match l with - | [] -> l0 - | _::l' when i=0 -> List.rev_append acc (x::l') - | y::l' -> - aux l' (y::acc) (i-1) - in - aux l0 [] i - -(*$T - set_at_idx 0 10 [1;2;3] = [10;2;3] - set_at_idx 4 10 [1;2;3] = [1;2;3] - set_at_idx 1 10 [1;2;3] = [1;10;3] -*) - -let insert_at_idx i x l = - let rec aux l acc i x = match l with - | [] -> List.rev_append acc [x] - | y::l' when i=0 -> List.rev_append acc (x::y::l') - | y::l' -> - aux l' (y::acc) (i-1) x - in - aux l [] i x - -(*$T - insert_at_idx 0 10 [1;2;3] = [10;1;2;3] - insert_at_idx 4 10 [1;2;3] = [1;2;3;10] - insert_at_idx 1 10 [1;2;3] = [1;10;2;3] -*) - -let remove_at_idx i l0 = - let rec aux l acc i = match l with - | [] -> l0 - | _::l' when i=0 -> List.rev_append acc l' - | y::l' -> - aux l' (y::acc) (i-1) - in - aux l0 [] i - -(*$T - remove_at_idx 0 [1;2;3;4] = [2;3;4] - remove_at_idx 3 [1;2;3;4] = [1;2;3] - remove_at_idx 5 [1;2;3;4] = [1;2;3;4] -*) - -let range_by ~step i j = - let rec range i j acc = - if i=j then i::acc else range i (j-step) (j::acc) - in - if step = 0 then - raise (Invalid_argument "CCList.range_by") - else if (if step > 0 then i>j else i \ - let i = min i j and j = max i j in \ - range_by ~step:1 i j = range i j) -*) - -let range i j = - let rec up i j acc = - if i=j then i::acc else up i (j-1) (j::acc) - and down i j acc = - if i=j then i::acc else down i (j+1) (j::acc) - in - if i<=j then up i j [] else down i j [] - -(*$T - range 0 5 = [0;1;2;3;4;5] - range 0 0 = [0] - range 5 2 = [5;4;3;2] -*) - -let range' i j = - if i \ - let l = (a--^b) in not (List.mem b l)) -*) - -let replicate i x = - let rec aux acc i = - if i = 0 then acc - else aux (x::acc) (i-1) - in aux [] i - -let repeat i l = - let l' = List.rev l in - let rec aux acc i = - if i = 0 then List.rev acc - else aux (List.rev_append l' acc) (i-1) - in aux [] i - -module Assoc = struct - type ('a, 'b) t = ('a*'b) list - - let rec search_exn eq l x = match l with - | [] -> raise Not_found - | (y,z)::l' -> - if eq x y then z else search_exn eq l' x - - let get_exn ?(eq=(=)) x l = search_exn eq l x - - let get ?(eq=(=)) x l = - try Some (search_exn eq l x) - with Not_found -> None - - (*$T - Assoc.get 1 [1, "1"; 2, "2"] = Some "1" - Assoc.get 2 [1, "1"; 2, "2"] = Some "2" - Assoc.get 3 [1, "1"; 2, "2"] = None - Assoc.get 42 [] = None - *) - - (* search for a binding for [x] in [l], and calls [f x (Some v) rest] - or [f x None rest] depending on whether it finds the binding. - [rest] is the list of the other bindings *) - let rec search_set eq acc l x ~f = match l with - | [] -> f x None acc - | (x',y')::l' -> - if eq x x' - then f x (Some y') (List.rev_append acc l') - else search_set eq ((x',y')::acc) l' x ~f - - let set ?(eq=(=)) x y l = - search_set eq [] l x - ~f:(fun x _ l -> (x,y)::l) - - (*$T - Assoc.set 2 "two" [1,"1"; 2, "2"] |> List.sort Pervasives.compare \ - = [1, "1"; 2, "two"] - Assoc.set 3 "3" [1,"1"; 2, "2"] |> List.sort Pervasives.compare \ - = [1, "1"; 2, "2"; 3, "3"] - *) - - let mem ?(eq=(=)) x l = - try ignore (search_exn eq l x); true - with Not_found -> false - - (*$T - Assoc.mem 1 [1,"1"; 2,"2"; 3, "3"] - not (Assoc.mem 4 [1,"1"; 2,"2"; 3, "3"]) - *) - - let update ?(eq=(=)) ~f x l = - search_set eq [] l x - ~f:(fun x opt_y rest -> - match f opt_y with - | None -> rest (* drop *) - | Some y' -> (x,y') :: rest) - (*$= - [1,"1"; 2,"22"] \ - (Assoc.update 2 [1,"1"; 2,"2"] \ - ~f:(function Some "2" -> Some "22" | _ -> assert false) |> lsort) - [1,"1"; 3,"3"] \ - (Assoc.update 2 [1,"1"; 2,"2"; 3,"3"] \ - ~f:(function Some "2" -> None | _ -> assert false) |> lsort) - [1,"1"; 2,"2"; 3,"3"] \ - (Assoc.update 3 [1,"1"; 2,"2"] \ - ~f:(function None -> Some "3" | _ -> assert false) |> lsort) - *) - - let remove ?(eq=(=)) x l = - search_set eq [] l x - ~f:(fun _ opt_y rest -> match opt_y with - | None -> l (* keep as is *) - | Some _ -> rest) - - (*$= - [1,"1"] \ - (Assoc.remove 2 [1,"1"; 2,"2"] |> lsort) - [1,"1"; 3,"3"] \ - (Assoc.remove 2 [1,"1"; 2,"2"; 3,"3"] |> lsort) - [1,"1"; 2,"2"] \ - (Assoc.remove 3 [1,"1"; 2,"2"] |> lsort) - *) -end - -(** {2 References on Lists} *) - -module Ref = struct - type 'a t = 'a list ref - - let push l x = l := x :: !l - - let pop l = match !l with - | [] -> None - | x::tail -> - l := tail; - Some x - - let pop_exn l = match !l with - | [] -> failwith "CCList.Ref.pop_exn" - | x::tail -> - l := tail; - x - - let create() = ref [] - - let clear l = l := [] - - let lift f l = f !l - - let push_list r l = - r := List.rev_append l !r - - (*$T - let l = Ref.create() in Ref.push l 1; Ref.push_list l [2;3]; !l = [3;2;1] - *) -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) = struct - open M - - let map_m f l = - let rec aux f acc l = match l with - | [] -> return (List.rev acc) - | x::tail -> - f x >>= fun x' -> - aux f (x' :: acc) tail - in aux f [] l - - 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 - x' >>= fun x' -> - tl' >>= fun tl' -> - M.return (x'::tl') - - let sequence_m l = map_m (fun x->x) l - - let rec fold_m f acc l = match l with - | [] -> return acc - | x :: l' -> - f acc x - >>= fun acc' -> - fold_m f acc' l' -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 - -let random_len len g st = - init len (fun _ -> g st) - -(*$T - random_len 10 CCInt.random_small (Random.State.make [||]) |> List.length = 10 -*) - -let random g st = - let len = Random.State.int st 1_000 in - random_len len g st - -let random_non_empty g st = - let len = 1 + Random.State.int st 1_000 in - random_len len g st - -let random_choose l = match l with - | [] -> raise Not_found - | _::_ -> - let len = List.length l in - fun st -> - let i = Random.State.int st len in - List.nth l i - -let random_sequence l st = map (fun g -> g st) l - -let to_seq l k = List.iter k l -let of_seq seq = - let l = ref [] in - seq (fun x -> l := x :: !l); - List.rev !l - -let to_gen l = - let l = ref l in - fun () -> - match !l with - | [] -> None - | x::l' -> - l := l'; Some x - -let of_gen g = - let rec direct i g = - if i = 0 then safe [] g - else match g () with - | None -> [] - | Some x -> x :: direct (i-1) g - and safe acc g = match g () with - | None -> List.rev acc - | Some x -> safe (x::acc) g - in - direct direct_depth_default_ g - -let to_klist l = - let rec make l () = match l with - | [] -> `Nil - | x::l' -> `Cons (x, make l') - in make l - -let of_klist l = - let rec direct i g = - if i = 0 then safe [] g - else match l () with - | `Nil -> [] - | `Cons (x,l') -> x :: direct (i-1) l' - and safe acc l = match l () with - | `Nil -> List.rev acc - | `Cons (x,l') -> safe (x::acc) l' - in - direct direct_depth_default_ l - -module Infix = struct - let (>|=) = (>|=) - let (@) = (@) - let (<*>) = (<*>) - let (<$>) = (<$>) - let (>>=) = (>>=) - let (--) = (--) - let (--^) = (--^) -end - -(** {2 IO} *) - -let pp ?(start="") ?(stop="") ?(sep=", ") pp_item fmt l = - let rec print fmt l = match l with - | x::((_::_) as l) -> - pp_item fmt x; - Format.pp_print_string fmt sep; - Format.pp_print_cut fmt (); - print fmt l - | x::[] -> pp_item fmt x - | [] -> () - in - Format.pp_print_string fmt start; - print fmt l; - Format.pp_print_string fmt stop - -(*$= & ~printer:(fun s->s) - "[1, 2, 3]" \ - (CCFormat.to_string \ - (CCFormat.hbox(CCList.pp ~start:"[" ~stop:"]" CCFormat.int)) \ - [1;2;3]) -*) +include CCList From 7d88c0f068c6f40001c5bbcfb3c272a43e82097f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Wos=CC=81?= Date: Wed, 6 Dec 2017 19:35:54 +0900 Subject: [PATCH 2/2] Update AUTHORS --- AUTHORS.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.adoc b/AUTHORS.adoc index b31a8f64..79736e19 100644 --- a/AUTHORS.adoc +++ b/AUTHORS.adoc @@ -23,3 +23,4 @@ - Leonid Rozenberg (@rleonid) - Bikal Gurung (@bikalgurung) - Fabian Hemmer (copy) +- Maciej Woś (@lostman)