(* This version from 1 April 2015 *)
module Juli8 = struct
(*
module Std = struct
include Pervasives
module List = List
end
*)
external ident : 'a -> 'a = "%identity"
let const c = (); fun _ -> c
(* TODO: include fun x y -> f (g x y)? include flip (%)? *)
let (%) f g = (); fun x -> f (g x)
let flip f = (); fun x y -> f y x
let fix (f : ('a -> 'b) -> ('a -> 'b)) : 'a -> 'b = let rec x y = f x y in x
(* Haskell's `(op rightval)` = `flip (op) rightval` *)
(* Haskell's `f $ xxx $ yyy` == `f @@ xxx @@ yyy` which is properly right-associative.
If you `let ($$) = (@@)`, then `f $$ xxx $$ yyy` will be `f (xxx) (yyy)`. *)
(* `non p` == `not % p` *)
let non f = (); fun x -> not (f x)
let non2 f = (); fun x y -> not (f x y)
let pair x y = (x, y)
let swap (x, y) = (y, x)
let curry f = (); fun x y -> f (x, y)
let uncurry f = (); fun (x, y) -> f x y
let mapfst f (x, y) = (f x, y)
let mapsnd f (x, y) = (x, f y)
let even x = x land 1 = 0
let odd x = x land 1 = 1
let sign x = if x < 0 then -1 else if x > 0 then 1 else 0
exception Overflow
let pred x = if x < 0 then invalid_arg "pred" else if x > 0 then x - 1 else raise Overflow
let pred' x = if x < 0 then invalid_arg "pred'" else if x > 0 then x - 1 else 0
let sub x y = if x < 0 || y < 0 then invalid_arg "sub" else if x >= y then x - y else raise Overflow
let sub' x y = if x < 0 || y < 0 then invalid_arg "sub'" else if x >= y then x - y else 0
let mid x y = x land y + ((x lxor y) asr 1)
let pow (x : int) (n : int) : int =
let rec aux x n =
if n = 1 then x
else
let y = aux x (n asr 1) in
y * y * (if n land 1 = 0 then 1 else x) in
if n < 0 then invalid_arg "pow"
else if n = 0 then 1
else aux x n
let undefined () = failwith "undefined"
let finally handler f x =
let res = (try f x with e -> handler(); raise e) in
handler(); res
(* Haskell's `last $ take n $ iterate s z`, might also call `ntimes` *)
let rec iterate (n : int) s z =
if n <= 0 then z
else iterate (n - 1) s (s z)
(* Haskell's `head $ dropWhile p $ iterate s z`; or `until (not.p) s z` *)
let rec iter_while p s z =
if p z then iter_while p s (s z) else z
(* let forever f x = while true do f x done *)
let rec forever f x = ignore(f x); forever f x
module Option : sig
val some : 'a -> 'a option
val test : ('a -> bool) -> 'a -> 'a option
val is_some : 'a option -> bool
val is_none : 'a option -> bool
val unsome : exn -> 'a option -> 'a (* Haskell's `fromJust` *)
val optcatch : ('a -> 'b) -> 'a -> 'b option
val string_of_option : ('a -> string) -> 'a option -> string
val list_of_option : 'a option -> 'a list (* Haskell's `maybeToList` *)
(* List.opthead is Haskell's `listToMaybe` *)
val default : 'a -> 'a option -> 'a (* Haskell's `fromMaybe` *)
val mapdefault : 'b -> ('a -> 'b) -> 'a option -> 'b (* Haskell's `maybe` *)
(* List.optmap is Haskell's `mapMaybe` *)
val length : 'a option -> int
val mem : ?eq:('a -> 'a -> bool) -> 'a -> 'a option -> bool
val map : ('a -> 'b) -> 'a option -> 'b option
val map2 : ('a -> 'b -> 'c) -> 'a option -> 'b option -> 'c option
val filter : ('a -> bool) -> 'a option -> 'a option
end = struct
let some x = Some x
let test p x = if p x then Some x else None
let is_some = function Some _ -> true | _ -> false
let is_none = function None -> true | _ -> false
let unsome exn = function Some a -> a | None -> raise exn
let optcatch f a = try Some (f a) with _ -> None
let string_of_option f = function Some a -> "Some " ^ f a | None -> "None"
let list_of_option = function Some a -> [a] | None -> []
let default def = function Some a -> a | None -> def
let mapdefault def f = function Some a -> f a | None -> def
let length = function Some _ -> 1 | None -> 0
let mem ?(eq=(=)) sought = function Some y -> eq y sought | None -> false
let map f = function Some a -> Some (f a) | None -> None
let map2 f u v = match u,v with Some x,Some y -> Some (f x y) | _ -> None
let filter p = function Some a as orig when p a -> orig | _ -> None
end
let some = Option.some
let is_some = Option.is_some
let is_none = Option.is_none
let unsome = Option.unsome
let string_of_option = Option.string_of_option
let list_of_option = Option.list_of_option
module List : sig
(*
Some functions in this module accept labels: ~short, ~onto:_, ~rev, ~cmp:_, ~eq:_, ~missing:_, ~step:_, ~many, ~len:_.
~short (map2, zip, iter2, fold_left2, fold_right2) means you don't require the lists to be the same length. (NOT provided for for_all2, exists2)
~onto:[] is for efficiency (rev, map, mapi, map2, zip, unmap2, unzip, optmap, optmapi, catmap, catmapi, filter, unfold, mapz).
~rev sometimes (map, optmap, catmap, map2, zip, unmap2, unzip, filter, unfold, mapz) means you don't require the output to correspond to input order, and thus can get more efficient implementation.
For sort and is_sorted, ~rev reverses the direction of ~cmp (first match will still come first/be retained if not ~many).
~rev other times (max/minimum, max/minby, take_while, drop_while, split_while, find[x], optfind, index, remove, delete, pick[x], assoc/assq, [opt]modify_assoc/assq, remove_assoc/assq) means find last match rather than first.
Find/remove from end: find[x]/optfind/index ~rev, remove/delete ~rev, pick[x] ~rev; also assoc/assq, [opt]modify_assoc/assq, remove_assoc/assq.
Find/remove all: filter[x]/indices, remove/delete ~many, partition[x]. (`remove ~many` is `filter (non p)`); also remove_assoc/assq ~many and diff ~many.
These have a default ~cmp: max/minimum, max/minby, lexcmp, sort, is_sorted, insert, merge (the latter two assume ordered lists). Other times (mem, index, delete, [is_]unique, is_subset, diff, union, intersect) ~cmp:_ asserts the list is ordered, and ignores any ~eq specification.
Functions seeking a specific member/key may specify the ~eq:(=) function (mem, index, delete, indices, assoc, mem_assoc, [opt]modify_assoc, remove_assoc).
Other functions using ~eq: group, [is_]unique, is_eqset, is_subset/list, diff, union, intersect, histogram.
See also memq, indexq, deleteq, indicesq, assq, mem_assq, [opt]modify_assq, remove_assq.
Additionally, modify_assoc/assq accepts an optional ~missing:(fun k -> v) alongside its (fun k v -> v); else it raises Not_found. pairwise accepts optional ~missing:'a to supply a snd for the last element.
Additionally, range and range_until accept ~step, and range's second argument can be tagged ~len.
Additionally, insert and sort accept an optional ~many to insert/keep items even if they cmp 0 to existing members. is_sorted ~many interprets "sorted" to permit duplicates; and is_subset ~many permits multiplicity of subset to > super. See also remove/delete ~many and remove_assoc/assq ~many and diff ~many.
sublists and permutations accept optional ~len, and can also be invoked as ~len:_ ~many to mean with replacement.
Functions in this module may raise:
* Invalid_argument for indices < 0, or length < 0 for make, or ~step:0 for range/_until
* Invalid argument when specifying both ~cmp and ~rev to index, delete; or both ~many and ~rev to remove, delete.
* Invalid_argument when is_subset without ~cmp or ~many; or when sublists/permutations ~many without ~len
* Not_found
* Short_list, e.g. head []; map2 f [] [...] without ~short; indices >= length
Primed versions of tail, init, take, drop, split: silently accommodate short lists. (Compare pred', sub'.)
*)
(* TODO: cycle n xs *)
(* IFFY names: unmap2, mapz, min/maxby, chunk[']/chunk_int/chunk_range, is_eqset, indexq/indicesq/deleteq *)
val short : unit
val many : unit
exception Short_list
val is_null : 'a list -> bool
val length : 'a list -> int
val count : ('a -> bool) -> 'a list -> int
val cons : 'a -> 'a list -> 'a list
val snoc : 'a list -> 'a -> 'a list
val singleton : 'a -> 'a list
val make : int -> 'a -> 'a list (* Haskell's `replicate` *)
val head : 'a list -> 'a
val opthead : 'a list -> 'a option
val tail : 'a list -> 'a list
val tail' : 'a list -> 'a list
val uncons : 'a list -> 'a * 'a list
val last : 'a list -> 'a
val init : 'a list -> 'a list
val init' : 'a list -> 'a list
val append : 'a list -> 'a list -> 'a list
val concat : 'a list list -> 'a list
val rev : ?onto:'a list -> 'a list -> 'a list (* Haskell's `reverse` *)
val mem : 'a -> ?eq:('a -> 'a -> bool) -> ?cmp:('a -> 'a -> int) -> 'a list -> bool (* Haskell's `elem` *)
val map : ('a -> 'b) -> ?rev:'c -> ?onto:'b list -> 'a list -> 'b list
val map2 : ('a -> 'b -> 'c) -> ?rev:'d -> ?onto:'c list -> ?short:'e -> 'a list -> 'b list -> 'c list (* Haskell's `zipWith` *)
val unmap2 : ('c -> 'a * 'b) -> ?rev:'d -> ?onto:'a list * 'b list -> 'c list -> 'a list * 'b list
val zip : ?rev:'d -> ?onto:('a * 'b) list -> ?short:'e -> 'a list -> 'b list -> ('a * 'b) list (* aka `Std.List.combine` or `map2 pair` *)
val unzip : ?rev:'d -> ?onto:'b list * 'c list -> ('b * 'c) list -> 'b list * 'c list (* aka `Std.List.split` or `unmap2 ident` *)
val mapi : (int -> 'a -> 'b) -> ?onto:'b list -> 'a list -> 'b list
val optmap : ('a -> 'b option) -> ?rev:'c -> ?onto:'b list -> 'a list -> 'b list
val optmapi : (int -> 'a -> 'b option) -> ?onto:'b list -> 'a list -> 'b list
(* `catmap f ~rev [x1,x2,x3]` ==> [x3c..x3a; x2c..x2a; x1c..x1a] *)
val catmap : ('a -> 'b list) -> ?rev:'c -> ?onto:'b list -> 'a list -> 'b list (* Haskell's `concatMap` *)
val catmapi : (int -> 'a -> 'b list) -> ?onto:'b list -> 'a list -> 'b list
val iter : ('a -> unit) -> 'a list -> unit
val iteri : (int -> 'a -> unit) -> 'a list -> unit
val iter2 : ('a -> 'b -> unit) -> ?short:'c -> 'a list -> 'b list -> unit
val fold_left : ('z -> 'a -> 'z) -> 'z -> 'a list -> 'z
val fold_left1 : ('a -> 'a -> 'a) -> 'a list -> 'a
val fold_left2 : ('z -> 'a -> 'b -> 'z) -> 'z -> ?short:'d -> 'a list -> 'b list -> 'z
val fold_right : ('a -> 'z -> 'z) -> 'a list -> 'z -> 'z
val fold_right1 : ('a -> 'a -> 'a) -> 'a list -> 'a
val fold_right2 : ('a -> 'b -> 'z -> 'z) -> ?short:'d -> 'a list -> 'b list -> 'z -> 'z
val for_all : ('a -> bool) -> 'a list -> bool (* Haskell's `all` *)
val exists : ('a -> bool) -> 'a list -> bool (* Haskell's `any` *)
val for_all2 : ('a -> 'b -> bool) -> 'a list -> 'b list -> bool
val exists2 : ('a -> 'b -> bool) -> 'a list -> 'b list -> bool
val maximum : ?rev:'b -> ?cmp:('a -> 'a -> int) -> 'a list -> 'a
val minimum : ?rev:'b -> ?cmp:('a -> 'a -> int) -> 'a list -> 'a
(* These compare mapped values, and return index,original,mapped value. *)
val maxby : ('a -> 'b) -> ?cmp:('b -> 'b -> int) -> ?rev:'c -> 'a list -> int * 'a * 'b
val minby : ('a -> 'b) -> ?cmp:('b -> 'b -> int) -> ?rev:'c -> 'a list -> int * 'a * 'b
val sum : int list -> int
val product : int list -> int
val take : int -> 'a list -> 'a list
val take' : int -> 'a list -> 'a list
val drop : int -> 'a list -> 'a list (* `tail` is `drop 1` *)
val drop' : int -> 'a list -> 'a list
val split : int -> 'a list -> 'a list * 'a list
val split' : int -> 'a list -> 'a list * 'a list (* Haskell's `splitAt` *)
val nth : 'a list -> int -> 'a (* Haskell's `xs !! n` *)
val modify : int -> ('a -> 'a) -> 'a list -> 'a list
val optmodify : int -> ('a -> 'a option) -> 'a list -> 'a list
val catmodify : int -> ('a -> 'a list) -> 'a list -> 'a list
val take_while : ('a -> bool) -> ?rev:'b -> 'a list -> 'a list
val drop_while : ('a -> bool) -> ?rev:'b -> 'a list -> 'a list
(* `split_while p xs` is `(take_while p xs, drop_while p xs)`; but `split_while p ~rev xs` is `(drop_while p ~rev xs, take_while p ~rev xs)` *)
val split_while : ('a -> bool) -> ?rev:'b -> 'a list -> 'a list * 'a list (* Haskell's `span` *)
val find : ('a -> bool) -> ?rev:'b -> 'a list -> 'a
val optfind : ('a -> 'b option) -> ?rev:'c -> 'a list -> 'b
val findx : ('a -> bool) -> ?rev:'b -> 'a list -> int * 'a (* fst of this is Haskell's `findIndex`, except that returns Maybe Int *)
(* Unlike findx, index accepts ~cmp. *)
val index : 'a -> ?rev:'b -> ?eq:('a -> 'a -> bool) -> ?cmp:('a -> 'a -> int) -> 'a list -> int (* Haskell's `elemIndex`, except that returns Maybe Int *)
val remove : ('a -> bool) -> ?rev:'b -> ?many:'c -> 'a list -> 'a list
val delete : 'a -> ?rev:'b -> ?eq:('a -> 'a -> bool) -> ?cmp:('a -> 'a -> int) -> ?many:'c -> 'a list -> 'a list
(* `pick p xs` is `(find p xs, remove p xs)` *)
val pick : ('a -> bool) -> ?rev:'b -> 'a list -> 'a * 'a list
val pickx : ('a -> bool) -> ?rev:'b -> 'a list -> int * 'a * 'a list
val filter : ('a -> bool) -> ?rev:'b -> ?onto:'a list -> 'a list -> 'a list
val filterx : ('a -> bool) -> 'a list -> (int * 'a) list (* fst of this is Haskell's `findIndices` *)
val indices : 'a -> ?eq:('a -> 'a -> bool) -> 'a list -> int list (* Haskell's `elemIndices` *)
(* `partition p xs` is `(filter p xs, filter (non p) xs)` *)
val partition : ('a -> bool) -> 'a list -> 'a list * 'a list
val partitionx : ('a -> bool) -> 'a list -> (int * 'a) list * (int * 'a) list
val assoc : 'a -> ?rev:'c -> ?eq:('a -> 'a -> bool) -> ('a * 'b) list -> 'b (* Haskell's `lookup` *)
val mem_assoc : 'a -> ?eq:('a -> 'a -> bool) -> ('a * 'b) list -> bool
val modify_assoc : 'a -> ('a -> 'b -> 'b) -> ?missing:('a -> 'b) -> ?rev:'c -> ?eq:('a -> 'a -> bool) -> ('a * 'b) list -> ('a * 'b) list
val optmodify_assoc : 'a -> ('a -> 'b option -> 'b option) -> ?rev:'c -> ?eq:('a -> 'a -> bool) -> ('a * 'b) list -> ('a * 'b) list
val remove_assoc : 'a -> ?rev:'c -> ?eq:('a -> 'a -> bool) -> ?many:'d -> ('a * 'b) list -> ('a * 'b) list
val memq : 'a -> 'a list -> bool
val indexq : 'a -> 'a list -> int
val deleteq : 'a -> 'a list -> 'a list
val indicesq : 'a -> 'a list -> int list
val assq : 'a -> ?rev:'c -> ('a * 'b) list -> 'b
val mem_assq : 'a -> ('a * 'b) list -> bool
val modify_assq : 'a -> ('a -> 'b -> 'b) -> ?missing:('a -> 'b) -> ?rev:'c -> ('a * 'b) list -> ('a * 'b) list
val optmodify_assq : 'a -> ('a -> 'b option -> 'b option) -> ?rev:'c -> ('a * 'b) list -> ('a * 'b) list
val remove_assq : 'a -> ?rev:'c -> ?many:'d -> ('a * 'b) list -> ('a * 'b) list
(* Positive n rotates forward; `rotate 1 xs` is `append (last xs) (init xs)` or `unsnoc` *)
val rotate : int -> 'a list -> 'a list
val unfold : ('z -> ('a * 'z) option) -> ?rev:'c -> ?onto:'a list -> 'z -> 'a list
(* ~rev only affects the order of the mapz'd output, not the direction of the folding *)
val mapz : ('z -> 'a -> 'z * 'b) -> 'z -> ?rev:'d -> ?onto:'b list -> 'a list -> 'z * 'b list (* Haskell's `mapAccumL` *)
val group : ?eq:('a -> 'a -> bool) -> 'a list -> 'a list list (* Haskell's `groupBy` *)
(* `cross f xs ys` is `[f x y | x from xs, y from ys]` or `catmap (fun x -> map (f x) ys) xs` *)
val cross : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list
(* `insert` expects a sorted list; use `catmodify` to insert elements before/after a specified index *)
val insert : 'a -> ?cmp:('a -> 'a -> int) -> ?many:'b -> 'a list -> 'a list
(* Plural version of `nth` *)
val select : 'a list -> int list -> 'a list
(* `range start ~len` *)
val range : ?step:int -> int -> len:int -> int list
(* `range_until start excluded_stop`; specify ~step:1 to produce [] when stop < start *)
val range_until : ?step:int -> int -> int -> int list
val unique : ?cmp:('a -> 'a -> int) -> ?eq:('a -> 'a -> bool) -> 'a list -> 'a list (* Haskell's `nub` *)
val is_unique : ?cmp:('a -> 'a -> int) -> ?eq:('a -> 'a -> bool) -> 'a list -> bool
(* `transpose [xxx, yyy]` ==> [xy, xy, xy] *)
val transpose : 'a list list -> 'a list list
(* Based on http://www.haskell.org/ghc/docs/latest/html/libraries/base/src/Data-List.html#permutations
Permutations with replacement, or enum base xs of 0..pow (length xs) k-1, is Haskell's `replicateM k xs` or `sequence $ replicate k xs`; same as `cross klist (make k xs)` *)
val permutations : ?len:int -> ?many:'b -> 'a list -> 'a list list
(* `sublists` without ~len or ~many is powerlist/all combinations, preserving order of members, who needn't have been contiguous; is Haskell's `subsequences` or `filterM (const [False, True]) xs`.
sublists ~len:k gives combinations of length k; straightforward implementation, found at http://www.polyomino.f2s.com/david/haskell/hs/CombinatoricsGeneration.hs.txt, also http://rosettacode.org/wiki/Combinations#Haskell
sublists ~len:k ~many gives the ((length xs+k-1) choose k) many combinations with replacement; based on http://rosettacode.org/wiki/Combinations_with_repetitions#Haskell *)
val sublists : ?len:int -> ?many:'b -> 'a list -> 'a list list
(* Members of first arg must appear in order in second, though they needn't be contiguous; for sorted lists, is a less-efficient version of `is_subset` without ~many *)
val is_sublist : ?eq:('a -> 'a -> bool) -> 'a list -> 'a list -> bool
(* `let sup = [1] in is_subset ~many [1;1] sup` is true; omit ~many to require sup to have >= the multiplicity of each member of subset *)
val is_subset : ?cmp:('a -> 'a -> int) -> ?eq:('a -> 'a -> bool) -> ?many:'b -> 'a list -> 'a list -> bool
(* Multiset equality, order ignored *)
val is_eqset : ?eq:('a -> 'a -> bool) -> 'a list -> 'a list -> bool
val lexcmp : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list -> int
(* `diff ~many xs ys` deletes all occurrences of each member of ys *)
val diff : ?cmp:('a -> 'a -> int) -> ?eq:('a -> 'a -> bool) -> ?many:'b -> 'a list -> 'a list -> 'a list
(* Each element has its max multiplicity; with second list always as a suffix of the result *)
val union : ?cmp:('a -> 'a -> int) -> ?eq:('a -> 'a -> bool) -> 'a list -> 'a list -> 'a list
(* Each element has its min multiplicity; in order of second list *)
val intersect : ?cmp:('a -> 'a -> int) -> ?eq:('a -> 'a -> bool) -> 'a list -> 'a list -> 'a list
(* To merge without ~many, use `union ~cmp:compare`. *)
val merge : ?cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list
(* Stable mergesort, O(n log n) avg and worst, will delete later occurrences of any duplicates, unless invoked with ~many *)
val sort : ?cmp:('a -> 'a -> int) -> ?many:'b -> ?rev:'c -> 'a list -> 'a list
val is_sorted : ?cmp:('a -> 'a -> int) -> ?many:'b -> ?rev:'c -> 'a list -> bool
val string_of_list : ?brackets:bool -> ?sep:string -> ('a -> string) -> 'a list -> string
val histogram : ?eq:('a -> 'a -> bool) -> 'a list -> ('a * int) list
(* [x1;x2;x3] ==> [(x1,x2);(x2,x3);(x3,missing)] *)
val pairwise : ?missing:'a -> 'a list -> ('a * 'a) list
(* [xxxx,y,zz] ==> xyzxzxx *)
val round_robin : 'a list list -> 'a list
(* Break list into int-sized discrete segments; chunk' permits last chunk to be short *)
val chunk : int -> 'a list -> 'a list list
val chunk' : int -> 'a list -> 'a list list
(* How many ways can int be represented as sum of members of xs (permitting them to be re-used)?
`chunk_int 6 [1;2;3]` ==> [ [3;3]; [3;2;1]; [3;1;1;1]; ...]
These are sometimes called "partitions of N". Based on http://www.polyomino.f2s.com/david/haskell/hs/CombinatoricsGeneration.hs.txt. This is an NP problem. *)
val chunk_int : int -> int list -> int list list
(* Partitions of the range 0..(k1+k2+k3) into lists of size k1,k2,k3.
`chunk_range [2;1;3]` ==> [ [[0;1];[2];[3;4;5]]; ...]
Based on http://rosettacode.org/wiki/Ordered_Partitions#Haskell *)
val chunk_range : int list -> int list list list
end = struct
let short = ()
let many = ()
exception Short_list
let is_null = function [] -> true | _ -> false
let length xs =
let rec aux i = function [] -> i | _::xs -> aux (i+1) xs in
aux 0 xs
let count p xs =
let rec aux p n = function [] -> n | x::xs when p x -> aux p (n+1) xs | _::xs -> aux p n xs in
aux p 0 xs
let cons x xs = x :: xs
let singleton x = [x]
let make n x =
let rec aux x xs n = if n = 0 then xs else aux x (x::xs) (n-1) in
if n < 0 then invalid_arg "make" else aux x [] n
let rec rev1 onto = function [] -> onto | x::xs -> rev1 (x::onto) xs
let rec rev2 onto = function [] -> onto | ys::yss -> rev2 (rev1 onto ys) yss
let rec rev ?(onto=[]) = function [] -> onto | x::xs -> let onto = x::onto in rev ~onto xs
let snoc xs x = rev1 [x] (rev1 [] xs)
let head = function x::_ -> x | [] -> raise Short_list
let opthead = function x::_ -> Some x | [] -> None
let tail = function _::xs -> xs | [] -> raise Short_list
let tail' = function _::xs -> xs | [] -> []
let uncons = function x::xs -> (x,xs) | [] -> raise Short_list
let rec last = function [x] -> x | x::xs -> last xs | _ -> raise Short_list
let init xs = match rev1 [] xs with [] -> raise Short_list | _::xs -> rev1 [] xs
let init' xs = match rev1 [] xs with [] -> [] | _::xs -> rev1 [] xs
let append xs = function [] -> xs | onto -> rev1 onto (rev1 [] xs)
let concat xss = rev2 [] (rev1 [] xss)
let mem sought ?(eq=(=)) ?cmp xs =
let rec aux_all eq sought = function [] -> false | x::xs -> eq x sought || aux_all eq sought xs in
let rec aux_sorted cmp sought = function
| x::xs -> let res = cmp x sought in if res > 0 then false else res = 0 || aux_sorted cmp sought xs
| [] -> false in
match cmp with
| None -> aux_all eq sought xs
| Some cmp -> aux_sorted cmp sought xs
let rec memq sought = function [] -> false | x::xs -> x == sought || memq sought xs
let map f ?rev ?(onto=[]) xs =
let rec aux f onto = function
| [] -> onto
| x::xs -> aux f (f x::onto) xs in
match rev with
| None -> rev1 onto (aux f [] xs)
| Some _ -> aux f onto xs
let map2 f ?rev ?(onto=[]) ?short xs ys =
let rec aux f short onto xs ys = match xs, ys with
| x::xs, y::ys -> aux f short (f x y::onto) xs ys
| [],[] -> onto
| _ -> if short then onto else raise Short_list in
match rev with
| None -> rev1 onto (aux f (Option.is_some short) [] xs ys)
| Some _ -> aux f (Option.is_some short) onto xs ys
let zip ?rev ?(onto=[]) ?short xs ys =
let rec aux short onto xs ys = match xs, ys with
| x::xs, y::ys -> aux short ((x,y)::onto) xs ys
| [],[] -> onto
| _ -> if short then onto else raise Short_list in
match rev with
| None -> rev1 onto (aux (Option.is_some short) [] xs ys)
| Some _ -> aux (Option.is_some short) onto xs ys
let unmap2 f ?rev ?(onto=[],[]) zs =
let rec aux f xs ys = function
| [] -> xs, ys
| z::zs -> let x,y = f z in aux f (x::xs) (y::ys) zs in
match rev,onto with
| None,(xonto,yonto) -> let xs,ys = aux f [] [] zs in rev1 xonto xs, rev1 yonto ys
| Some _,(xonto,yonto) -> aux f xonto yonto zs
let unzip ?rev ?(onto=[],[]) zs =
let rec aux xs ys = function
| [] -> xs, ys
| (x,y)::zs -> aux (x::xs) (y::ys) zs in
match rev,onto with
| None,(xonto,yonto) -> let xs,ys = aux [] [] zs in rev1 xonto xs, rev1 yonto ys
| Some _,(xonto,yonto) -> aux xonto yonto zs
let mapi f ?(onto=[]) xs =
let rec aux f i onto = function
| [] -> onto
| x::xs -> aux f (i+1) (f i x::onto) xs in
rev1 onto (aux f 0 [] xs)
let optmap f ?rev ?(onto=[]) xs =
let rec aux f onto = function
| [] -> onto
| x::xs -> aux f (match f x with None -> onto | Some x' -> x'::onto) xs in
match rev with
| None -> rev1 onto (aux f [] xs)
| Some _ -> aux f onto xs
let optmapi f ?(onto=[]) xs =
let rec aux f i onto = function
| [] -> onto
| x::xs -> aux f (i+1) (match f i x with None -> onto | Some x' -> x'::onto) xs in
rev1 onto (aux f 0 [] xs)
let catmap f ?rev ?(onto=[]) xs =
let rec aux f onto = function
| [] -> onto
| x::xs -> aux f (rev1 [] (f x)::onto) xs in
let rec aux_rev f onto = function
| [] -> onto
| x::xs -> aux_rev f (rev1 onto (f x)) xs in
match rev with
| None -> rev2 onto (aux f [] xs)
| Some _ -> aux_rev f onto xs
let catmapi f ?(onto=[]) xs =
let rec aux f i onto = function
| [] -> onto
| x::xs -> aux f (i+1) (rev1 [] (f i x)::onto) xs in
rev2 onto (aux f 0 [] xs)
let rec iter f = function [] -> () | x::xs -> f x; iter f xs
let iteri f xs =
let rec aux f i = function [] -> () | x::xs -> f i x; aux f (i+1) xs in
aux f 0 xs
let iter2 f ?short xs ys =
let rec aux f short xs ys = match xs, ys with
| x::xs, y::ys -> f x y; aux f short xs ys
| [],[] -> ()
| _ -> if short then () else raise Short_list in
aux f (Option.is_some short) xs ys
let rec fold_left f z = function
| [] -> z
| x::xs -> fold_left f (f z x) xs
let fold_left1 f = function
| [] -> raise Short_list
| x::xs -> fold_left f x xs
let fold_left2 f z ?short xs ys =
let rec aux f short z xs ys = match xs, ys with
| [],[] -> z
| x::xs,y::ys -> aux f short (f z x y) xs ys
| _ -> if short then z else raise Short_list in
aux f (Option.is_some short) z xs ys
let rec fold_right f xs z =
let rec aux f z = function
| [] -> z
| x::xs -> aux f (f x z) xs in
aux f z (rev1 [] xs)
let fold_right1 f xs =
let rec aux f z = function
| [] -> z
| x::xs -> aux f (f x z) xs in
match rev1 [] xs with
| [] -> raise Short_list
| x::xs -> aux f x xs
let fold_right2 f ?short xs ys z =
let rec aux f short z xs ys = match xs, ys with
| [],[] -> z
| x::xs,y::ys -> aux f short (f x y z) xs ys
| _ -> if short then z else raise Short_list in
aux f (Option.is_some short) z (rev1 [] xs) (rev1 [] ys)
let rec for_all p = function [] -> true | x::xs -> p x && for_all p xs
let rec exists p = function [] -> false | x::xs -> p x || exists p xs
let rec for_all2 p xs ys = match xs,ys with [],[] -> true | x::xs,y::ys -> p x y && for_all2 p xs ys | _ -> raise Short_list
let rec exists2 p xs ys = match xs,ys with [],[] -> false | x::xs,y::ys -> p x y || exists2 p xs ys | _ -> raise Short_list
let maximum ?rev ?(cmp=compare) xs =
let rec aux select cmp sofar = function
| [] -> sofar
| x::xs -> let res = cmp x sofar in aux select cmp (if res < 0 then sofar else if res = 0 then select sofar x else x) xs in
match rev,xs with
| None,(x::xs) -> aux (fun sofar x -> sofar) cmp x xs
| Some _,(x::xs) -> aux (fun sofar x -> x) cmp x xs
| _ -> raise Short_list
let minimum ?rev ?(cmp=compare) xs =
let rec aux select cmp sofar = function
| [] -> sofar
| x::xs -> let res = cmp x sofar in aux select cmp (if res > 0 then sofar else if res = 0 then select sofar x else x) xs in
match rev,xs with
| None,(x::xs) -> aux (fun sofar x -> sofar) cmp x xs
| Some _,(x::xs) -> aux (fun sofar x -> x) cmp x xs
| _ -> raise Short_list
(*
let maximumx ?rev ?(cmp=compare) xs =
let rec aux select cmp i sofar = function
| [] -> sofar
| x::xs -> let res = cmp x (snd sofar) in aux select cmp (i+1) (if res < 0 then sofar else if res = 0 then select sofar i x else (i,x)) xs in
match rev,xs with
| None,(x::xs) -> aux (fun sofar i x -> sofar) cmp 1 (0,x) xs
| Some _,(x::xs) -> aux (fun sofar i x -> (i,x)) cmp 1 (0,x) xs
| _ -> raise Short_list
let minimumx ?rev ?(cmp=compare) xs =
let rec aux select cmp i sofar = function
| [] -> sofar
| x::xs -> let res = cmp x (snd sofar) in aux select cmp (i+1) (if res > 0 then sofar else if res = 0 then select sofar i x else (i,x)) xs in
match rev,xs with
| None,(x::xs) -> aux (fun sofar i x -> sofar) cmp 1 (0,x) xs
| Some _,(x::xs) -> aux (fun sofar i x -> (i,x)) cmp 1 (0,x) xs
| _ -> raise Short_list
*)
let maxby f ?(cmp=compare) ?rev xs =
let rec aux f cmp thresh (_,_,fw as prev) i = function
| [] -> prev
| x::xs -> aux f cmp thresh (let fx = f x in if cmp fx fw > thresh then (i,x,fx) else prev) (i+1) xs in
match rev,xs with
| _,[] -> raise Short_list
| None,x::xs -> aux f cmp 0 (0,x,f x) 1 xs
| Some _,x::xs -> aux f cmp (-1) (0,x,f x) 1 xs
let minby f ?(cmp=compare) ?rev xs =
let rec aux f cmp thresh (_,_,fw as prev) i = function
| [] -> prev
| x::xs -> aux f cmp thresh (let fx = f x in if cmp fx fw < thresh then (i,x,fx) else prev) (i+1) xs in
match rev,xs with
| _,[] -> raise Short_list
| None,x::xs -> aux f cmp 0 (0,x,f x) 1 xs
| Some _,x::xs -> aux f cmp (+1) (0,x,f x) 1 xs
let sum xs = fold_left ( + ) 0 xs
let product xs = fold_left ( * ) 1 xs
let take n xs =
let rec aux n ys = function
| _ when n = 0 -> rev1 [] ys
| [] -> raise Short_list
| x::xs -> aux (n-1) (x::ys) xs in
if n < 0 then invalid_arg "take" else aux n [] xs
let take' n xs =
let rec aux n ys = function
| _ when n = 0 -> rev1 [] ys
| [] -> rev1 [] ys
| x::xs -> aux (n-1) (x::ys) xs in
if n < 0 then invalid_arg "take'" else aux n [] xs
let drop n xs =
let rec aux n = function
| xs when n = 0 -> xs
| [] -> raise Short_list
| _::xs -> aux (n-1) xs in
if n < 0 then invalid_arg "drop" else aux n xs
let drop' n xs =
let rec aux n = function
| xs when n = 0 -> xs
| [] -> []
| _::xs -> aux (n-1) xs in
if n < 0 then invalid_arg "drop'" else aux n xs
let split n xs =
let rec aux n ys = function
| xs when n = 0 -> rev1 [] ys, xs
| [] -> raise Short_list
| x::xs -> aux (n-1) (x::ys) xs in
if n < 0 then invalid_arg "split" else aux n [] xs
let split' n xs =
let rec aux n ys = function
| xs when n = 0 -> rev1 [] ys, xs
| [] -> rev1 [] ys, []
| x::xs -> aux (n-1) (x::ys) xs in
if n < 0 then invalid_arg "split'" else aux n [] xs
let nth xs n =
let rec aux n = function
| x::xs -> if n = 0 then x else aux (n-1) xs
| [] -> raise Short_list in
if n < 0 then invalid_arg "nth" else aux n xs
let modify n f xs =
let rec aux n f i ys = function
| [] -> raise Short_list
| x::xs -> if n = i then rev1 ((f x)::xs) ys else aux n f (i+1) (x::ys) xs in
if n < 0 then invalid_arg "modify" else aux n f 0 [] xs
let optmodify n f xs =
let rec aux n f i ys = function
| [] -> raise Short_list
| x::xs -> if n = i then rev1 (match f x with Some x -> x::xs | None -> xs) ys else aux n f (i+1) (x::ys) xs in
if n < 0 then invalid_arg "optmodify" else aux n f 0 [] xs
let catmodify n f xs =
let rec aux n f i ys = function
| [] -> raise Short_list
| x::xs -> if n = i then rev1 xs (rev1 ys (f x)) else aux n f (i+1) (x::ys) xs in
if n < 0 then invalid_arg "optmodify" else aux n f 0 [] xs
let take_while p ?rev xs =
let rec aux_left p ys = function
| [] -> xs
| x::xs -> if p x then aux_left p (x::ys) xs else rev1 [] ys in
let rec aux_right p ys = function
| [] -> rev1 [] ys
| x::xs -> if p x then aux_right p (x::ys) xs else aux_right p [] xs in
match rev with
| None -> aux_left p [] xs
| Some _ -> aux_right p [] xs
let drop_while p ?rev xs =
let rec aux_left p = function
| [] -> []
| x::xs as orig -> if p x then aux_left p xs else orig in
let rec aux_right p matching yss ys = function
| [] -> if matching then rev2 [] yss else xs
| x::xs -> if p x = matching then aux_right p matching yss (x::ys) xs
else aux_right p (not matching) (ys::yss) [x] xs in
match rev with
| None -> aux_left p xs
| Some _ -> aux_right p false [] [] xs
let split_while p ?rev xs =
let rec aux_left p ys = function
| [] -> xs, []
| x::xs as orig -> if p x then aux_left p (x::ys) xs else rev1 [] ys, orig in
let rec aux_right p matching yss ys = function
| [] -> if matching then rev2 [] yss, rev1 [] ys else xs, []
| x::xs -> if p x = matching then aux_right p matching yss (x::ys) xs
else aux_right p (not matching) (ys::yss) [x] xs in
match rev with
| None -> aux_left p [] xs
| Some _ -> aux_right p false [] [] xs
let find p ?rev xs =
let rec aux_left p = function [] -> raise Not_found | x::xs -> if p x then x else aux_left p xs in
let rec aux_right p prev = function
| [] -> (match prev with None -> raise Not_found | Some x -> x)
| x::xs -> aux_right p (if p x then Some x else prev) xs in
match rev with
| None -> aux_left p xs
| Some _ -> aux_right p None xs
let optfind p ?rev xs =
let rec aux_left p = function [] -> raise Not_found | x::xs -> (match p x with Some y -> y | None -> aux_left p xs) in
let rec aux_right p prev = function
| [] -> (match prev with None -> raise Not_found | Some x -> x)
| x::xs -> aux_right p (match p x with Some y -> Some y | None -> prev) xs in
match rev with
| None -> aux_left p xs
| Some _ -> aux_right p None xs
let findx p ?rev xs =
let rec aux_left p i = function [] -> raise Not_found | x::xs -> if p x then (i,x) else aux_left p (i+1) xs in
let rec aux_right p i prev = function
| [] -> (match prev with None -> raise Not_found | Some (i,x as res) -> res)
| x::xs -> aux_right p (i+1) (if p x then Some (i,x) else prev) xs in
match rev with
| None -> aux_left p 0 xs
| Some _ -> aux_right p 0 None xs
let index sought ?rev ?(eq=(=)) ?cmp xs =
let rec aux_left eq sought i = function [] -> raise Not_found | x::xs -> if eq x sought then i else aux_left eq sought (i+1) xs in
let rec aux_right eq sought i prev = function [] -> if prev < 0 then raise Not_found else prev | x::xs -> aux_right eq sought (i+1) (if eq x sought then i else prev) xs in
let rec aux_sorted cmp sought i = function
| x::xs -> let res = cmp x sought in if res > 0 then raise Not_found else if res = 0 then i else aux_sorted cmp sought (i+1) xs
| [] -> raise Not_found in
match cmp,rev with
| None,None -> aux_left eq sought 0 xs
| None,Some _ -> aux_right eq sought 0 (-1) xs
| Some cmp,None -> aux_sorted cmp sought 0 xs
| Some _,Some _ -> invalid_arg "index ~rev conflicts with ~cmp"
let indexq sought xs =
let rec aux sought i = function [] -> raise Not_found | x::xs -> if x == sought then i else aux sought (i+1) xs in
aux sought 0 xs
let remove p ?rev ?many xs =
let rec aux_left p ys = function [] -> xs | x::xs -> if p x then rev1 xs ys else aux_left p (x::ys) xs in
let rec aux_many p ys = function [] -> rev1 [] ys | x::xs -> aux_many p (if p x then ys else x::ys) xs in
let rec aux_right p yss ys = function
| [] -> (match yss with [] -> xs | (_::xs)::yss -> rev2 (rev1 [] ys) (xs::yss) | _ -> assert false)
| x::xs -> if p x then aux_right p ((x::ys)::yss) [] xs else aux_right p yss (x::ys) xs in
match rev,many with
| None,None -> aux_left p [] xs
| Some _,None -> aux_right p [] [] xs
| None,Some _ -> aux_many p [] xs
| Some _,Some _ -> invalid_arg "remove ~rev conflicts with ~many"
let delete sought ?rev ?(eq=(=)) ?cmp ?many xs =
let rec aux_left eq sought ys = function [] -> xs | x::xs -> if eq x sought then rev1 xs ys else aux_left eq sought (x::ys) xs in
let rec aux_many eq sought ys = function [] -> rev1 [] ys | x::xs -> aux_many eq sought (if eq x sought then ys else x::ys) xs in
let rec aux_right eq sought yss ys = function
| [] -> (match yss with [] -> xs | (_::xs)::yss -> rev2 (rev1 [] ys) (xs::yss) | _ -> assert false)
| x::xs -> if eq x sought then aux_right eq sought ((x::ys)::yss) [] xs else aux_right eq sought yss (x::ys) xs in
let rec aux_sorted cmp sought ys = function
| [] -> xs
(* don't shadow the entry-level `xs` *)
| z::zs -> let res = cmp z sought in if res > 0 then xs else if res = 0 then rev1 zs ys else aux_sorted cmp sought (z::ys) zs in
let rec aux_msorted cmp sought ys = function
| [] -> rev1 [] ys
| x::xs as orig -> let res = cmp x sought in if res > 0 then rev1 orig ys else aux_msorted cmp sought (if res = 0 then ys else x::ys) xs in
match cmp,rev,many with
| None,None,None -> aux_left eq sought [] xs
| None,Some _,None -> aux_right eq sought [] [] xs
| Some cmp,None,None -> aux_sorted cmp sought [] xs
| None,None,Some _ -> aux_many eq sought [] xs
| Some cmp,None,Some _ -> aux_msorted cmp sought [] xs
| Some _,Some _,None -> invalid_arg "delete ~rev conflicts with ~cmp"
| None,Some _,Some _ -> invalid_arg "delete ~rev conflicts with ~many"
| Some _,Some _,Some _ -> invalid_arg "delete ~rev conflicts with ~many and ~cmp"
let deleteq sought xs =
let rec aux sought ys = function [] -> xs | x::xs -> if x == sought then rev1 xs ys else aux sought (x::ys) xs in
aux sought [] xs
let pick p ?rev xs =
let rec aux_left p ys = function [] -> raise Not_found | x::xs -> if p x then x, rev1 xs ys else aux_left p (x::ys) xs in
let rec aux_right p prev yss ys = function
| [] -> (match prev, yss with None,_ -> raise Not_found | Some x,(_::xs)::yss -> x, rev2 (rev1 [] ys) (xs::yss) | _ -> assert false)
| x::xs -> if p x then aux_right p (Some x) ((x::ys)::yss) [] xs else aux_right p prev yss (x::ys) xs in
match rev with
| None -> aux_left p [] xs
| Some _ -> aux_right p None [] [] xs
let pickx p ?rev xs =
let rec aux_left p i ys = function [] -> raise Not_found | x::xs -> if p x then i, x, rev1 xs ys else aux_left p (i+1) (x::ys) xs in
let rec aux_right p i prev yss ys = function
| [] -> (match prev, yss with None,_ -> raise Not_found | Some (i,x),(_::xs)::yss -> i, x, rev2 (rev1 [] ys) (xs::yss) | _ -> assert false)
| x::xs -> if p x then aux_right p (i+1) (Some (i,x)) ((x::ys)::yss) [] xs else aux_right p (i+1) prev yss (x::ys) xs in
match rev with
| None -> aux_left p 0 [] xs
| Some _ -> aux_right p 0 None [] [] xs
let filter p ?rev ?(onto=[]) xs =
let rec aux p ys = function [] -> ys | x::xs -> aux p (if p x then x::ys else ys) xs in
match rev with
| None -> rev1 onto (aux p [] xs)
| Some _ -> aux p onto xs
(*
val filteri : (int -> 'a -> bool) -> ?onto:'a list -> 'a list -> 'a list
let filteri p ?(onto=[]) xs =
let rec aux p i ys = function [] -> ys | x::xs -> aux p (i+1) (if p i x then x::ys else ys) xs in
rev1 onto (aux p 0 [] xs)
*)
let filterx p xs =
let rec aux p i ys = function [] -> ys | x::xs -> aux p (i+1) (if p x then (i,x)::ys else ys) xs in
rev1 [] (aux p 0 [] xs)
let indices sought ?(eq=(=)) xs =
let rec aux eq sought i ys = function [] -> ys | x::xs -> aux eq sought (i+1) (if eq x sought then i::ys else ys) xs in
rev1 [] (aux eq sought 0 [] xs)
let indicesq sought xs =
let rec aux sought i ys = function [] -> ys | x::xs -> aux sought (i+1) (if x == sought then i::ys else ys) xs in
rev1 [] (aux sought 0 [] xs)
(* remove ~many p, delete ~many x *)
let partition p xs =
let rec aux p ys ns = function
| [] -> if ys = [] then [], xs else if ns = [] then xs, [] else rev1 [] ys, rev1 [] ns
| x::xs -> if p x then aux p (x::ys) ns xs else aux p ys (x::ns) xs in
aux p [] [] xs
let partitionx p xs =
let rec aux p i ys ns = function
| [] -> rev1 [] ys, rev1 [] ns
| x::xs -> if p x then aux p (i+1) ((i,x)::ys) ns xs else aux p (i+1) ys ((i,x)::ns) xs in
aux p 0 [] [] xs
let assoc sought ?rev ?(eq=(=)) xs =
let rec aux_left sought eq = function
| [] -> raise Not_found
| (k,x)::xs -> if eq k sought then x else aux_left sought eq xs in
let rec aux_right sought eq prev = function
| [] -> (match prev with None -> raise Not_found | Some x -> x)
| (k,x)::xs -> aux_right sought eq (if eq k sought then Some x else prev) xs in
match rev with
| None -> aux_left sought eq xs
| Some _ -> aux_right sought eq None xs
let rec assq sought ?rev xs =
let rec aux_left sought = function
| [] -> raise Not_found
| (k,x)::xs -> if k == sought then x else assq sought xs in
let rec aux_right sought prev = function
| [] -> (match prev with None -> raise Not_found | Some x -> x)
| (k,x)::xs -> aux_right sought (if k == sought then Some x else prev) xs in
match rev with
| None -> aux_left sought xs
| Some _ -> aux_right sought None xs
let modify_assoc sought f ?missing ?rev ?(eq=(=)) xs =
let rec aux_left sought f eq ys = function
| [] -> None
| (k,x as kx)::xs -> if eq k sought then Some (rev1 ((k,f k x)::xs) ys) else aux_left sought f eq (kx::ys) xs in
let rec aux_right sought f eq yss ys = function
| [] -> (match yss with [] -> None | ((k,x)::xs)::yss -> Some (rev2 ((k,f k x)::rev1 [] ys) (xs::yss)) | _ -> assert false)
| (k,x as kx)::xs -> if eq k sought then aux_right sought f eq ((kx::ys)::yss) [] xs else aux_right sought f eq yss (kx::ys) xs in
match rev,missing with
| None,None -> (match aux_left sought f eq [] xs with None -> raise Not_found | Some xs -> xs)
| None,Some m -> (match aux_left sought f eq [] xs with None -> (sought,m sought)::xs | Some xs -> xs)
| Some _,None -> (match aux_right sought f eq [] [] xs with None -> raise Not_found | Some xs -> xs)
| Some _,Some m -> (match aux_right sought f eq [] [] xs with None -> (sought,m sought)::xs | Some xs -> xs)
let optmodify_assoc sought f ?rev ?(eq=(=)) xs =
let rec aux_left sought f eq ys = function
| [] -> None
| (k,x as kx)::xs -> if eq k sought then Some (rev1 (match f k (Some x) with None -> xs | Some x -> (k,x)::xs) ys) else aux_left sought f eq (kx::ys) xs in
let rec aux_right sought f eq yss ys = function
| [] -> (match yss with [] -> None | ((k,x)::xs)::yss -> Some (rev2 (match f k (Some x) with None -> rev1 [] ys | Some x -> (k,x)::rev1 [] ys) (xs::yss)) | _ -> assert false)
| (k,x as kx)::xs -> if eq k sought then aux_right sought f eq ((kx::ys)::yss) [] xs else aux_right sought f eq yss (kx::ys) xs in
match rev with
| None -> (match aux_left sought f eq [] xs with None -> (match f sought None with None -> xs | Some x -> (sought,x)::xs) | Some xs -> xs)
| Some _ -> (match aux_right sought f eq [] [] xs with None -> (match f sought None with None -> xs | Some x -> (sought,x)::xs) | Some xs -> xs)
let modify_assq sought f ?missing ?rev xs =
let rec aux_left sought f ys = function
| [] -> None
| (k,x as kx)::xs -> if k == sought then Some (rev1 ((k,f k x)::xs) ys) else aux_left sought f (kx::ys) xs in
let rec aux_right sought f yss ys = function
| [] -> (match yss with [] -> None | ((k,x)::xs)::yss -> Some (rev2 ((k,f k x)::rev1 [] ys) (xs::yss)) | _ -> assert false)
| (k,x as kx)::xs -> if k == sought then aux_right sought f ((kx::ys)::yss) [] xs else aux_right sought f yss (kx::ys) xs in
match rev,missing with
| None,None -> (match aux_left sought f [] xs with None -> raise Not_found | Some xs -> xs)
| None,Some m -> (match aux_left sought f [] xs with None -> (sought,m sought)::xs | Some xs -> xs)
| Some _,None -> (match aux_right sought f [] [] xs with None -> raise Not_found | Some xs -> xs)
| Some _,Some m -> (match aux_right sought f [] [] xs with None -> (sought,m sought)::xs | Some xs -> xs)
let optmodify_assq sought f ?rev xs =
let rec aux_left sought f ys = function
| [] -> None
| (k,x as kx)::xs -> if k == sought then Some (rev1 (match f k (Some x) with None -> xs | Some x -> (k,x)::xs) ys) else aux_left sought f (kx::ys) xs in
let rec aux_right sought f yss ys = function
| [] -> (match yss with [] -> None | ((k,x)::xs)::yss -> Some (rev2 (match f k (Some x) with None -> rev1 [] ys | Some x -> (k,x)::rev1 [] ys) (xs::yss)) | _ -> assert false)
| (k,x as kx)::xs -> if k == sought then aux_right sought f ((kx::ys)::yss) [] xs else aux_right sought f yss (kx::ys) xs in
match rev with
| None -> (match aux_left sought f [] xs with None -> (match f sought None with None -> xs | Some x -> (sought,x)::xs) | Some xs -> xs)
| Some _ -> (match aux_right sought f [] [] xs with None -> (match f sought None with None -> xs | Some x -> (sought,x)::xs) | Some xs -> xs)
let rec mem_assoc sought ?(eq=(=)) = function
| [] -> false
| (k,_)::xs -> eq k sought || mem_assoc ~eq sought xs
let rec mem_assq sought = function
| [] -> false
| (k,_)::xs -> k == sought || mem_assq sought xs
let remove_assoc sought ?rev ?(eq=(=)) ?many xs =
let rec aux_left sought eq ys = function
| [] -> xs
| (k,_ as kx)::xs -> if eq k sought then rev1 xs ys else aux_left sought eq (kx::ys) xs in
let rec aux_many sought eq ys = function
| [] -> rev1 [] ys
| (k,_ as kx)::xs -> aux_many sought eq (if eq k sought then ys else kx::ys) xs in
let rec aux_right sought eq yss ys = function
| [] -> (match yss with [] -> xs | (_::xs)::yss -> rev2 (rev1 [] ys) (xs::yss) | _ -> assert false)
| (k,_ as kx)::xs -> if eq k sought then aux_right sought eq ((kx::ys)::yss) [] xs else aux_right sought eq yss (kx::ys) xs in
match rev,many with
| None,None -> aux_left sought eq [] xs
| Some _,None -> aux_right sought eq [] [] xs
| None,Some _ -> aux_many sought eq [] xs
| Some _,Some _ -> invalid_arg "remove_assoc ~rev conflicts with ~many"
let remove_assq sought ?rev ?many xs =
let rec aux_left sought ys = function
| [] -> xs
| (k,_ as kx)::xs -> if k == sought then rev1 xs ys else aux_left sought (kx::ys) xs in
let rec aux_many sought ys = function
| [] -> rev1 [] ys
| (k,_ as kx)::xs -> aux_many sought (if k == sought then ys else kx::ys) xs in
let rec aux_right sought yss ys = function
| [] -> (match yss with [] -> xs | (_::xs)::yss -> rev2 (rev1 [] ys) (xs::yss) | _ -> assert false)
| (k,_ as kx)::xs -> if k == sought then aux_right sought ((kx::ys)::yss) [] xs else aux_right sought yss (kx::ys) xs in
match rev,many with
| None,None -> aux_left sought [] xs
| Some _,None -> aux_right sought [] [] xs
| None,Some _ -> aux_many sought [] xs
| Some _,Some _ -> invalid_arg "remove_assq ~rev conflicts with ~many"
let rotate n xs =
let rec aux ys = function
| [x] -> x::rev1 [] ys
| x::xs -> aux (x::ys) xs
| _ -> assert false in
if n = 0 || xs = [] then xs
else if n = 1 then aux [] xs
else
let xn = length xs in
let n = (xn - n) mod xn in
let pre,post = if n > 0 then split n xs else if n < 0 then split (xn+n) xs else [],xs in
append post pre
let unfold f ?rev ?(onto=[]) z =
let rec aux f ys z = match f z with None -> ys | Some (y,z) -> aux f (y::ys) z in
match rev with
| None -> rev1 onto (aux f [] z)
| Some _ -> aux f onto z
let mapz f z ?rev ?(onto=[]) xs =
let rec aux f z ys = function [] -> z,ys | x::xs -> let z,y = f z x in aux f z (y::ys) xs in
match rev with
| None -> let z,ys = aux f z [] xs in z, rev1 onto ys
| Some _ -> aux f z onto xs
(*
let group ?(eq=(=)) xs =
let rec aux eq = function
| [] -> []
| x::xs -> let xs,ys = split_while (eq x) xs in (x::xs)::aux eq ys in
aux eq xs
*)
let group ?(eq=(=)) xs =
let f eq x = function [] -> [[x]] | (y::_ as ys)::yss -> if eq y x then (x::ys)::yss else [x]::ys::yss | _ -> assert false in
let rec aux f eq yss = function [] -> yss | x::xs -> aux f eq (f eq x yss) xs in
match aux f eq [] xs with [] -> [] | xs -> map ~rev rev xs
let cross f xs ys =
let rec aux f ys = function [] -> ys | x::xs -> aux f (f x::ys) xs in
rev2 [] (aux (fun x -> aux (f x) [] ys) [] xs)
let insert ins ?(cmp=compare) ?many xs =
let rec aux_one cmp ins ys = function
| [] -> rev1 [ins] ys
(* don't shadow the entry-level `xs` *)
| z::zs as orig -> let res = cmp z ins in if res < 0 then aux_one cmp ins (z::ys) zs else if res = 0 then xs else rev1 (ins::orig) ys in
let rec aux_many cmp ins ys = function
| [] -> rev1 [ins] ys
| x::xs as orig -> let res = cmp x ins in if res < 0 then aux_many cmp ins (x::ys) xs else rev1 (ins::orig) ys in
match many with
| None -> aux_one cmp ins [] xs
| Some _ -> aux_many cmp ins [] xs
let select xs is =
let rec aux j js i ys = function
| [] -> raise Short_list
(* don't shadow the entry-level `xs` *)
| z::zs as orig -> if j = i then (match js with j::js -> if j >= i then aux j js (if j = i then i else i+1) (z::ys) (if j = i then orig else zs) else aux j js 0 (z::ys) xs | [] -> rev1 [z] ys) else aux j js (i+1) ys zs in
match is with
| [] -> []
| i::is -> aux i is 0 [] xs
let range ?(step=1) start ~len =
let rec aux stop step ys i = if stop i then ys else aux stop step (i::ys) (i+step) in
if step = 0 then invalid_arg "range" else aux (if step > 0 then (fun i -> i < start) else (fun i -> i > start)) (-step) [] (start + len*step - step)
let range_until ?step start stop =
let rec aux stop step ys i = if stop i then ys else aux stop step (i::ys) (i+step) in
match step with
| None -> if stop <= start
then aux (fun i -> i > start) (1) [] (let len = (start - stop) in start - len + 1)
else aux (fun i -> i < start) (-1) [] (let len = (stop - start) in start + len - 1)
| Some x when x < 0 -> if stop >= start then [] else aux (fun i -> i > start) (-x) [] (let len = (stop + x + 1 - start) / x in start + len*x - x)
| Some x when x > 0 -> if stop <= start then [] else aux (fun i -> i < start) (-x) [] (let len = (stop + x - 1 - start) / x in start + len*x - x)
| _ -> invalid_arg "range_until"
let unique ?cmp ?(eq=(=)) xs =
let rec aux_mem eq x = function [] -> false | y::ys -> eq y x || aux_mem eq x ys in
let rec aux_all eq ys = function
| [] -> rev1 [] ys
| x::xs -> aux_all eq (if aux_mem eq x ys then ys else x::ys) xs in
let rec aux_sorted cmp ys y = function
| [] -> rev1 [y] ys
| x::xs -> if cmp y x = 0 then aux_sorted cmp ys y xs else aux_sorted cmp (y::ys) x xs in
match xs,cmp with
| [],_ | [_],_ -> xs
| x::xs, None -> aux_all eq [x] xs
| x::xs, Some cmp -> aux_sorted cmp [] x xs
let is_unique ?cmp ?(eq=(=)) xs =
let rec aux_mem eq sought = function [] -> false | x::xs -> eq x sought || aux_mem eq sought xs in
let rec aux_all eq ys = function
| [] -> true
| x::xs -> not (aux_mem eq x ys) && aux_all eq (x::ys) xs in
let rec aux_sorted cmp y = function
| [] -> true
| x::xs -> cmp y x < 0 && aux_sorted cmp x xs in
match xs,cmp with
| [],_ | [_],_ -> true
| x::xs, None -> aux_all eq [x] xs
| x::xs, Some cmp -> aux_sorted cmp x xs
let rec transpose = function
| [] -> []
| []::xss -> transpose xss
| (x::xs)::xss -> (x :: map head xss) :: transpose (xs :: map tail xss)
let sublists ?len ?many xs =
let rec aux_all = function [] -> [] | (x::xs) -> [x]::fold_left (fun yss ys -> (x::ys)::ys::yss) [] (aux_all xs) in
let rec aux_fixed k = function
| _ when k = 0 -> [[]]
| [] -> [] (* happens if k > length xs *)
| x::xs -> map (cons x) (aux_fixed (k-1) xs) ~onto:(aux_fixed k xs) in
let rec aux_replacing k = function
| _ when k = 0 -> [[]]
| [] -> [] (* will only happen if xs was [] to start with *)
| x::xs as orig -> map (cons x) (aux_replacing (k-1) orig) ~onto:(aux_replacing k xs) in
match len,many with
| None,None -> []::aux_all xs
| Some k,None -> if k < 0 then invalid_arg "sublists ~len" else aux_fixed k xs
| Some k,Some _ -> if k < 0 then invalid_arg "sublists ~len" else aux_replacing k xs
| None,Some _ -> invalid_arg "sublists ~many requires ~len"
let rec permutations ?len ?many xs =
let rec interleave' x xs f r = function
| [] -> xs, r
| y::ys -> let us,zs = interleave' x xs (fun ys -> f(y::ys)) r ys in y::us, f (x::y::us)::zs in
let interleave x xs r ys = let _,zs = interleave' x xs ident r ys in zs in
let rec aux ys = function
| [] -> []
| x::xs -> fold_left (interleave x xs) (aux (x::ys) xs) (permutations ys) in
let prod yss xs = catmap (fun x -> map (cons x) yss) xs in
match len,many with
| None,None -> xs::aux [] xs
| Some k,None -> if k < 0 then invalid_arg "permutations ~len" else catmap permutations (sublists ~len:k xs)
| Some k,Some _ -> if k < 0 then invalid_arg "permuations ~len" else if k = 0 then [] else fold_left prod [[]] (make k xs)
| None, Some _ -> invalid_arg "permutations ~many requires ~len"
let is_sublist ?(eq=(=)) xs ys =
let rec aux eq ys xs = match ys,xs with
| _,[] -> true
| [],_::_ -> false
| y::ys',x::xs' -> if eq y x then aux eq ys' xs' else aux eq ys' xs in
aux eq ys xs
let is_subset ?cmp ?(eq=(=)) ?many xs ys =
let rec aux_sorted uniq cmp ys xs = match ys,xs with
| _,[] -> true
| [],_::_ -> false
| y::ys',x::xs' -> let res = cmp y x in if res > 0 then false else if res < 0 then aux_sorted uniq cmp ys' xs else aux_sorted uniq cmp (if uniq then ys' else ys) xs' in
match cmp,many with
| None,Some _ -> for_all (fun x -> mem ~eq x ys) xs
| Some cmp,None -> aux_sorted true cmp ys xs
| Some cmp,Some _ -> aux_sorted false cmp ys xs
| None,None -> invalid_arg "is_subset requires ~cmp and/or ~many"
let is_eqset ?(eq=(=)) xs ys =
let rec aux eq x zs = function [] -> raise Not_found | y::ys -> if eq y x then x, rev1 ys zs else aux eq x (y::zs) ys in
try (match fold_left (fun ys x -> let _,ys = aux eq x [] ys in ys) ys xs with [] -> true | _ -> false)
with Not_found -> false
let rec lexcmp ?(cmp=compare) xs ys = match xs, ys with
| [],[] -> 0
| _,[] -> 1
| [],_ -> -1
| x::xs,y::ys -> let res = cmp x y in if res < 0 then -1 else if res > 0 then 1 else lexcmp ~cmp xs ys
let diff ?cmp ?(eq=(=)) ?many xs ys = fold_left (fun xs y -> delete ?cmp ~eq ?many y xs) xs ys
(*
let union ?cmp ?(eq=(=)) xs ys = append xs (fold_left (fun ys x -> delete ?cmp ~eq x ys) ys xs)
*)
let union ?cmp ?(eq=(=)) ys xs = append (fold_left (fun ys x -> delete ?cmp ~eq x ys) ys xs) xs
let intersect ?cmp ?(eq=(=)) xs ys =
let rec aux_all eq ws zs xs ys = match xs,ys with
| _,[] -> rev1 [] zs
| [],y::ys' -> aux_all eq [] zs (* don't need to reverse ws *) ws ys'
| x::xs',y::ys' -> if eq x y then aux_all eq [] (y::zs) (rev1 xs' ws) ys' else aux_all eq (x::ws) zs xs' ys in
let rec aux_sorted cmp zs xs ys = match xs,ys with
| [],_ | _,[] -> rev1 [] zs
| x::xs',y::ys' -> let res = cmp x y in if res < 0 then aux_sorted cmp zs xs' ys else if res > 0 then aux_sorted cmp zs xs ys' else aux_sorted cmp (y::zs) xs' ys' in
match cmp with
| None -> aux_all eq [] [] xs ys
| Some cmp -> aux_sorted cmp [] xs ys
let merge ?(cmp=compare) xs ys =
let rec aux cmp zs xs ys = match xs, ys with
| [],ys -> rev1 ys zs
| xs,[] -> rev1 xs zs
| x'::xs',y'::ys' -> if cmp x' y' <= 0 then aux cmp (x'::zs) xs' ys else aux cmp (y'::zs) xs ys' in
aux cmp [] xs ys
(*
"Natural" or "adaptive" bottom-up merge sort, inspired by http://www.drmaciver.com/tag/timsort/.
Optimized to exploit existing runs of ascending/descending elements, to consume at most O(log n) levels of its working stack,
and to be mostly tail-recursive, while minimizing how often sorted and merged runs need to be reversed.
Sort is stable, and has O(n log n) avg and worst-case behavior.
(Compare to naive mergesort on random data, also to C-implemented qsort, which isn't stable?)
Will delete (later occurrences of) any duplicates, unless invoked with ~many.
Copyright (c) 2012, 2015 by Dubiousjim .
See license at https://github.com/dubiousjim/unspoiled/blob/master/LICENSE
*)
let sort ?(cmp=compare) ?many ?rev xs =
let rec merge uniq cmp wasc yy zz ws wn =
assert (wasc <> 0); match yy,zz with
| us,[] | [],us -> rev1 ws us, wn, -wasc
| y::ys,z::zs -> let res = cmp y z in
if uniq && res = 0 then (assert (wn<>1); merge uniq cmp wasc ys zz ws (if wn = 0 then 0 else wn - 1))
else if (wasc < 0) = (res < 0) then merge uniq cmp wasc ys zz (y::ws) wn else merge uniq cmp wasc yy zs (z::ws) wn in
let rec merge1 uniq cmp ys yn yasc zss = match zss with
| [] -> None
| (z::zs' as zs,zn,zasc)::zss as orig -> (match ys with
| [] -> assert false
| y::ys' ->
(* yn = 0 forces collapse of stack *)
if yn > 0 && yn*2 <= zn then None
else let wn = if yn > 0 then yn + zn else 0 in
if yasc = 0 then (assert (yn <= 1); merge2 uniq cmp zss (merge uniq cmp zasc ys zs [] wn))
else let res = cmp y z in
let () = assert (yn <> 1) in
if uniq && res = 0 then (if yn = 1 then merge2 uniq cmp zss (zs,zn,zasc) else merge1 uniq cmp ys' (if yn = 0 then 0 else yn - 1) yasc orig)
else if yasc < 0 && zasc > 0 && res >= 0 then merge2 uniq cmp zss (rev1 zs ys, wn, 1)
else if yasc > 0 && zasc < 0 && res < 0 then merge2 uniq cmp zss (rev1 ys zs, wn, 1)
else let wasc,ys,zs = if (yasc < 0) = (zasc < 0) then zasc, ys, zs else if zn < yn then yasc, ys, rev1 [] zs else zasc, rev1 [] ys, zs in
merge2 uniq cmp zss (merge uniq cmp wasc ys zs [] wn))
| _ -> assert false
and merge2 uniq cmp zss (ws,wn,wasc) =
let more = merge1 uniq cmp ws wn wasc zss in
match more with None -> Some ((ws,wn,wasc)::zss) | _ -> more in
(* yasc = -1 when a segment of the original list was strictly descending, +1 when it was non-descending, 0 when the segment is only 1 member long *)
let rec step uniq cmp xs y ys yn yasc zss =
match xs with
| (x::xs) ->
let res = cmp x y in
if uniq && res = 0 then step uniq cmp xs y ys yn yasc zss
else if yn = 1 then step uniq cmp xs x (y::ys) 2 (if res < 0 then -1 else 1) zss
else (assert (yasc <> 0); if (yasc < 0) = (res < 0) then step uniq cmp xs x (y::ys) (yn+1) yasc zss
else step uniq cmp xs x [] 1 0 (match merge1 uniq cmp (y::ys) yn yasc zss with None -> (y::ys,yn,yasc)::zss | Some zss -> zss))
| [] -> (* finished stepping through original list, use yn = 0 to force merge1 until completion *)
(match merge1 uniq cmp (y::ys) 0 yasc zss with
| Some [(ys,0,yasc)] -> if yasc > 0 then rev1 [] ys else ys
| None -> if yasc > 0 then rev1 [y] ys else y::ys
| _ -> assert false) in
match many,rev,xs with
| _,_,[] | _,_,[_] -> xs
| None,None,x::xs -> step true cmp xs x [] 1 0 []
| Some _,None,x::xs -> step false cmp xs x [] 1 0 []
| None,Some _,x::xs -> step true (fun x y -> -cmp x y) xs x [] 1 0 []
| Some _,Some _,x::xs -> step false (fun x y -> -cmp x y) xs x [] 1 0 []
let is_sorted ?(cmp=compare) ?many ?rev xs =
let rec aux cmp thresh y = function
| [] -> true
| x::xs -> cmp y x < thresh && aux cmp thresh x xs in
match rev,xs with
| _,[] | _,[_] -> true
| None,x::xs -> aux cmp (match many with None -> 0 | Some _ -> 1) x xs
| Some _,x::xs -> aux (fun x y -> -cmp x y) (match many with None -> 0 | Some _ -> 1) x xs
let string_of_list ?(brackets=true) ?(sep=";") f xs =
let rec aux sep' = function [] -> if brackets then "]" else "" | x::xs -> sep' ^ f x ^ aux sep xs in
(if brackets then "[" else "") ^ aux "" xs
let histogram ?(eq=(=)) xs = fold_left (fun h x -> modify_assoc x (fun _ n -> n+1) ~missing:(fun _ -> 1) ~eq h) [] xs
let pairwise ?missing xs =
let rec aux missing x = function
| [] -> (match missing with None -> [] | Some y -> [(x,y)])
| y::ys -> (x,y)::aux missing y ys in
match xs with
| [] -> []
| x::xs -> aux missing x xs
let rec round_robin xss =
let rec aux ws ys = function
| [] -> (match ys with [] -> rev1 [] ws | _ -> aux ws [] (rev1 [] ys))
| []::xss -> aux ws ys xss
| (x::xs)::xss -> aux (x::ws) (xs::ys) xss in
match xss with
| [] -> raise Short_list
| []::xss -> round_robin xss
| xss -> aux [] [] xss
let rec chunk n xs = match split n xs with
| ys,[] -> [ys]
| ys,zs -> ys::chunk n zs
let rec chunk' n xs = match split' n xs with
| ys,[] -> [ys]
| ys,zs -> ys::chunk' n zs
let chunk_int n xs =
let rec aux n = function
| _ when n = 0 -> [[]]
| [] -> []
| x::xs as orig -> if x > n then aux n xs else map ~onto:(aux n xs) (cons x) (aux (n-x) orig) in
let xs = sort ~many xs in
match sort xs with x::_ as xs when x > 0 && n > 0 -> aux n (rev1 [] xs) | _ -> invalid_arg "chunk_int"
let chunk_range sizes =
let rec combs2 k = function
| xs when k = 0 -> [([],xs)]
| [] -> []
| x::xs -> map (fun (cs,zs) -> x::cs,zs) (combs2 (k-1) xs) ~onto:(map (fun (cs,zs) -> cs,x::zs) (combs2 k xs)) in
let rec p xs = function
| [] -> [[]]
| k::ks -> catmap (fun (cs,zs) -> map (cons cs) (p zs ks)) (combs2 k xs) in
if exists (fun x -> x<0) sizes then invalid_arg "chunk_range" else p (range_until 0 (sum sizes)) sizes
end (* List *)
let short = List.short
let many = List.many
exception Short_list = List.Short_list
let is_null = List.is_null
let length = List.length
let cons = List.cons
let snoc = List.snoc
let singleton = List.singleton
let head = List.head
let opthead = List.opthead
let tail = List.tail
let tail' = List.tail'
let uncons = List.uncons
let append = List.append
let concat = List.concat
let rev = List.rev
let zip = List.zip
let unzip = List.unzip
let iter = List.iter
let iteri = List.iteri
let iter2 = List.iter2
let fold_left = List.fold_left
let fold_left1 = List.fold_left1
let fold_left2 = List.fold_left2
let fold_right = List.fold_right
let fold_right1 = List.fold_right1
let fold_right2 = List.fold_right2
let for_all = List.for_all
let exists = List.exists
let for_all2 = List.for_all2
let exists2 = List.exists2
let sum = List.sum
let product = List.product
let take = List.take
let take' = List.take'
let drop = List.drop
let drop' = List.drop'
let split = List.split
let split' = List.split'
let nth = List.nth
(*
count
make
last
init
init'
mem
map
map2
unmap2
mapi
optmap
optmapi
catmap
catmapi
maximum
minimum
maxby
minby
modify
optmodify
catmodify
take_while
drop_while
split_while
find
optfind
findx
index
remove
delete
pick
pickx
filter
filterx
indices
partition
partitionx
assoc
mem_assoc
modify_assoc
optmodify_assoc
remove_assoc
memq
indexq
deleteq
indicesq
assq
mem_assq
modify_assq
optmodify_assq
remove_assq
rotate
unfold
mapz
group
cross
insert
select
range
range_until
unique
is_unique
transpose
permutations
sublists
is_sublist
is_subset
is_eqset
lexcmp
diff
union
intersect
merge
sort
is_sorted
string_of_list
histogram
pairwise
round_robin
chunk
chunk'
chunk_int
chunk_range
*)
let factorial n = let rec aux m = function 0 -> m | 1 -> m | n -> aux (n*m) (n-1) in aux 1 n
(* good to around n = 28; naive version overflows after n = 20 *)
let choose n k = let j = max k (n-k) in if j = n then 1 else List.fold_left (/) (List.product (List.range_until n j)) (List.range_until (n-j) 1)
module Random : sig
val init : ?seed:int -> unit -> unit
val bool : unit -> bool
(* start <= result < stop *)
val between : int -> int -> int
val nth : 'a list -> 'a
val pick : 'a list -> 'a * 'a list
(* k dice rolls are `permutation ~len:k ~many [1..6]` *)
val permutation : ?len:int -> ?many:'b -> 'a list -> 'a list
(* choose k elements from xs, in stable order, ~many with replacment *)
val sublist : len:int -> ?many:'b -> 'a list -> 'a list
end = struct
let init ?seed () =
match seed with
| None -> Std.Random.self_init()
| Some n -> Std.Random.init n
let bool = Std.Random.bool
let between start stop = Std.Random.int (stop-start) + start
let nth xs = match List.length xs with
| 0 -> invalid_arg "Random.nth"
| n -> List.nth xs (between 0 n)
let pick xs =
let rec aux n ws = function
| x::xs -> if n = 0 then x, List.rev ~onto:xs ws else aux (n-1) (x::ws) xs
| [] -> assert false in
match List.length xs with
| 0 -> invalid_arg "Random.pick"
| n -> aux (between 0 n) [] xs
let permutation ?len ?many xs =
(* a[j],a[n] = x,a[j] *)
let array_push a j n x = if j = n then a.(n) <- x else let y = a.(j) in (a.(j) <- x; a.(n) <- y) in
(* return,a[j] = a[j],a[n] *)
let array_pop a j n = let y = a.(n-1) in if j = n - 1 then y else (let x = a.(j) in a.(j) <- y; x) in
let rec aux_all a n = function
(* Based on https://en.wikipedia.org/wiki/Fisher-Yates_shuffle#The_.22inside-out.22_algorithm
Initialize empty array to shuffled copy of xs *)
| [] -> Array.to_list a
| x::xs -> let j = between 0 (n+1) in (array_push a j n x; aux_all a (n+1) xs) in
let rec aux_fixed k n a ws = function
| 0 -> ws
| i -> let j = between 0 n in let w = array_pop a j n in aux_fixed k (n-1) a (w::ws) (i-1) in
match len,many,xs with
| None,_,[] -> []
| Some k,_,[] -> if k = 0 then [] else invalid_arg "Random.permutation"
| None,None,x::_ -> aux_all (Array.make (List.length xs) x) 0 xs
| Some k,None,_ -> if k < 0 then invalid_arg "Random.permutation" else aux_fixed k (List.length xs) (Array.of_list xs) [] k
| Some k,Some _,_ -> if k < 0 then invalid_arg "Random.permutation" else iterate k (fun ys -> nth xs::ys) []
| None,Some _,_ -> invalid_arg "Random.permutation ~many requires ~len"
let sublist ~len:k ?many xs =
let rec aux_fixed ws n k = function
| _ when k = 0 -> List.rev ws
| (x::xs) ->
(* Explanation of the threshhold: There are n choose k many combinations, yes=(n-1) choose (k-1) headed by element x and no=(n-1) choose k not.
So x has yes/(yes+no) chance of occupying initial slot, else it occupies none of the slots. yes/(yes+no) reduces to k/n. *)
if between 0 n < k then aux_fixed (x::ws) (n-1) (k-1) xs else aux_fixed ws (n-1) k xs
| _ -> assert false in
let rec aux_replacing k top ws = function
| _ when k = 0 -> List.rev ws
| [] -> [] (* will only happen when xs was [] to start with *)
| x::xs as orig ->
(* Explanation of the threshhold: There are n+k-1 choose k many combinations with replacement, yes=(n+k-2) choose (k-1) headed by element x and no=(n+k-2) choose k not.
So x has yes/(yes+no) chance of occupying the initial slot, and also possibly some later slots. This reduces to k/(k+n-1). *)
if between 0 (k+top) < k then aux_replacing (k-1) top (x::ws) orig else aux_replacing k (top-1) ws xs in
let n = List.length xs in
if k < 0 || k > n then invalid_arg "Random.sublist"
else match many with
| None -> aux_fixed [] n k xs
| Some _ -> aux_replacing k (n-1) [] xs
end (* Random *)
(* #load "Str.cma";; *)
module String : sig
type t = string
val compare : 'a -> 'a -> int
val length : string -> int
val take : int -> ?rev:'a -> string -> string
val drop : int -> string -> string
val sub : string -> int -> len:int -> string
val is_prefix : string -> string -> bool
val is_suffix : string -> string -> bool
val is_infix : string -> string -> bool
val find : string -> ?rev:'a -> ?from:int -> string -> int
val nth : string -> int -> char
val make : int -> char -> string
val mem : char -> ?rev:'a -> ?from:int -> string -> bool
val index : ?rev:'a -> ?from:int -> char -> string -> int
val upper : string -> string
val lower : string -> string
val int_of_char : char -> int
val char_of_int : int -> char
(* trim only removes up to 1 leading/trailing occurrence of pat *)
val trim : string -> string
type pat = string
val split : string -> ?n:int -> ?trim:'a -> pat -> string list
val join : sep:string -> string list -> string
val lines : ?trim:'a -> string -> string list (* as in Haskell, gobbles up to 1 \n per line *)
val words : string -> string list
val unlines : string list -> string (* as in Haskell, does add a trailing \n *)
val unwords : string list -> string (* as in Haskell, no trailing space *)
end = struct
type t = string
let compare = compare
let length = Std.String.length
let take n ?rev s = match rev with
| None -> Str.string_before s n
| Some _ -> Str.last_chars s n
let drop n s = Str.string_after s n
let sub s start ~len = Std.String.sub s start len
let is_prefix (sought : string) s = let n = length sought in length s >= n && take n s = sought
let is_suffix (sought : string) s = let n = length sought in length s >= n && take n ~rev:() s = sought
let is_infix (sought : string) s = length sought <= length s && try Str.(search_forward (regexp_string sought) s 0) >= 0 with Not_found -> false
let find (sought : string) ?rev ?from s = match rev,from with
| None,None -> Str.(search_forward (regexp_string sought) s 0)
| None,Some n -> Str.(search_forward (regexp_string sought) s n)
| Some _,Some n -> Str.(search_backward (regexp_string sought) s n)
| Some _,None -> let n = length s - length sought in if n < 0 then raise Not_found else Str.(search_backward (regexp_string sought) s n)
let nth s n = Std.String.get s n
let make n c = Std.String.make n c
let mem (sought : char) ?rev ?from s = match rev,from with
| None,None -> Std.String.contains s sought
| None,Some n -> Std.String.contains_from s n sought
| Some _,Some n -> Std.String.rcontains_from s n sought
| Some _,None -> invalid_arg "String.mem ~rev requires ~from"
let index ?rev ?from (sought : char) s = match rev,from with
| None,None -> Std.String.index s sought
| Some _,None -> Std.String.rindex s sought
| None,Some n -> Std.String.index_from s n sought
| Some _,Some n -> Std.String.rindex_from s n sought
let upper s = Std.String.uppercase s
let lower s = Std.String.lowercase s
let int_of_char (c : char) = Std.Char.code c
let char_of_int (n : int) = Std.Char.chr n
let trim s = Std.String.trim s
type pat = string
let split s ?n ?trim pat = match n,trim with
| None,Some _ -> Str.(split (regexp pat) s)
| Some n,Some _ -> Str.(bounded_split (regexp pat) s n)
| None,None -> Str.(split_delim (regexp pat) s)
| Some n,None -> Str.(bounded_split_delim (regexp pat) s n)
let join ~sep ss = Std.String.concat sep ss
let lines ?trim s = split ("\n"^s) ~trim "\n"
let words s = split s ~trim "[ \t\n]+"
let unlines ss = join "\n" ss ^ "\n"
let unwords ss = join " " ss
end (* String *)
end (* Juli8 *)
open Juli8