PreludeSee the Example.
open Prelude (but it's not required)Prelude we include List; after opening Prelude, we have direct (unprefixed) access to all the functions in List, e.g. map, rev.include PrintfList.fold_left), so I provide aliases (e.g. foldl)Prelude has no dependencies on 3rd-party modules that don't come with the OCaml compiler (this requirement is temporarily untrue now that the latest versions of the compiler have dropped Stream syntax; I'm working on making this claim true again)You'll notice that I much prefer terse function names, especially since OCaml's nestable module system provides ready access to longer names via the module prefixes, and OCaml's local-open syntax allows these short names to be easily used without global namespace contamination.
Stdlib When You open PreludeOccasionally new functions are added to Stdlib modules, like Stdlib.List, whose names are already used in Prelude; this is something to be aware of if you open Prelude as I do. An example is that recently Stdlib.List acquired a compare function. Since Prelude opens List, this new compare would shadow Stdlib.compare, which is IMHO annoying.
My fix is to arrange that Prelude.compare is Stdlib.compare. The downside is that if you want Stdlib.List.compare you have to use the fully-qualified name, even though you've implicitly open'ed List. Since Stdlib.List.compare has a different type than Stdlib.compare, you'll always get a compile-time error if you ever get confused.
If there's anything about this you don't like, you can simply use Prelude without opening it.
Aspirationally, all modules that define data types should include the following functions:
random: to generate a random value of that typeto_string: to generate a string representation of any value of that typeprint: typically just (to_string >> print)I find these functions to be extremely useful for development and testing (especially in the top-level), and for unit tests.
ARITH, NULL, OrderedType, AIStringUnix.Timer, Unix.Env. Unix.Proc, Unix.Shellbenchmark, re, uri, xmlm.Many thanks to Matt TEICHMAN for lots of consultation, type wizardry, and especially for figuring out how to solve the dreaded int List.t = (::) (1, [2; 3]) top-level bug.
flip f x y: argument-flipping combinator (C combinator); returns (f y x). (flip (^) "a" "b") = "ba"
(whenever this that x) is (if x = this then that else x).
Example:
(argv |> whenever [] ["-"] |> iter (within process)) will invoke process on stdin if no files are in argv.
(curry f): converts a function on pairs to a curried function of two arguments.
(uncurry f): converts a curried function of two arguments to a function on pairs.
(tap f x): applies (f x) for side-effect, then returns x. ("foo" |> tap print |> String.length) prints "foo" and returns 3.
(|-) is (flip tap).
foo
|> List.map ...
|- (len >> printf "%d\n")
|> List.concat
|> ...(thunk f x) is (fun () -> f x), i.e. it wraps the application (f x) in a thunk.
y is the fixed-point finding Y-combinator; not tail-recursive.
y can be used to write recursive functions without using let rec: for example, given:
let fact_ fact x = if x = 0 then 1 else x * fact (x-1) then (y fact_ 6) = 720.
Perhaps more practically, y can be used, for example to trace a recursive function without signifcantly modifying the function definition:
let trace name f_ f x = let r = f_ f x in printf "%s %d -> %d\n" name x r; r and now:
# y (trace "fact" fact_) 6;;
fact 0 -> 1
fact 1 -> 1
fact 2 -> 2
fact 3 -> 6
fact 4 -> 24
fact 5 -> 120
fact 6 -> 720
_ : int = 720(fork (±) f g x) is (f x ± g x) and is the unary version of fork2.
N.B. this is J's fork conjunction (with monadic f and g, and dyadic (±)).
±
/ \
f g
| |
x yExample: (fork (/) sum len) is the arithmetic mean:
(fork (/) sum len (1--100)) = 50Example: (fork (-) maximum minimum) is the range of the ints in its list argument:
(fork (-) maximum minimum [2;8;5;4]) = 6(fork2 (±) ( × ) (÷) n m) is (n×m + n÷m) for arbitrary functions (+), ( × ), and (÷).
N.B. this is J's fork conjunction (with dyadic (±), ( × ), and (÷)).
±
/ \
× ÷
/ \ / \
n m n m(lefthook (±) (¬) x y) is (¬x ± y).
±
/ \
¬ y
|
xExample: (lefthook cons succ) = (conswith succ)
Example: fastest way to get the size of the data on an input channel like stdin:
Gen.(optional readblock $ fold (lefthook (+) String.len) 0) (<?) is lefthook.
Example: foldr (cons <? even) [] (0--4) = [true; false; true; false; true]
(righthook (±) (¬) x y) is (x ± ¬y).
±
/ \
x ¬
|
yExample: (righthook snoc succ) = (snocwith succ)
(>?) is righthook.
Example: foldl (snoc >? even) [] (0--4) = [true; false; true; false; true]
on (±) (¬) is (fun x y -> ¬x ± ¬y). Typically used to generate comparison functions for List.sort.
±
/ \
¬ ¬
| |
x yFor example, to sort an alist in reverse order of values, use:
(sort (on (flip compare) snd)) (on1 (±) (¬) x) is (fork (±) (¬) (¬)) i.e. (¬x ± ¬x).
±
/ \
¬ ¬
| |
x xExample: (on1 ( + ) (dbl ( * ))) x = (x*x) + (x*x)
A comparison function is one that compares two values and returns one of (-1, 0, 1) (e.g. OrderedType.compare).
See also Lists.comparison and AIString.compare.
(revcmp cmp) converts the comparison function cmp to one that compares in reverse order.
(cmpeq cmp) converts the comparison function cmp into an equality predicate.
These functions are flipped versions of the standard relational operators (<), (<=), (>), and (>=) (I throw in (=) and (<>) just for symmetry) and are intended to be used partially-applied. I think this function:
(len >> gt 64)
looks much better and is easier to understand than:
(len >> flip (>) 64)
or:
(len >> fun n -> n > 64)
or even, sometimes:
(fun xs -> len xs > 64)
YMMV!
(lt n) is true iff it is applied to a value strictly less than n.
lt is (flip (<)).
(lte n) is true iff it is applied to a value less than or equal to n.
lte is (flip (<=)).
(gt n) is true iff it is applied to a value strictly greater than n.
gt is (flip (>)).
(gte n) is true iff it is applied to a value greater than or equal to n.
gte is (flip (>=)).
(neq n) is true iff it is applied to a value not equal to n.
neq is just (<>).
(apply f x): function application: (apply f x) is exactly equivalent to (f x).
(@@) is apply; right associative.
This is Haskell's ($), and is useful for eliminating parentheses.
Example:
(print_endline (string_of_int (1 + 1))) = (print_endline @@ string_of_int @@ 1 + 1) (f << g): function composition: ((f << g) x) is exactly equivalent to (f (g x)).
This is Haskell's (.).
(f >> g): reverse function composition: ((f >> g) x) is exactly equivalent to (g (f x)).
(Failed_prerequisite cmds) is the type of exceptions raised by functions in Prereq.
module type NULL = sig ... endThe empty module.
module type OrderedType = sig ... end(sig type t val compare : t -> t -> int end).
module type TOSTRING = sig ... end(sig type t val to_string : t -> string end).
module type ARITH = sig ... endSignature for Arithmetics (type t, zero, succ, ( + ) and ( * )); we also include compare, one, pred, ( - ), ( / ), and random.
module Bool : sig ... endPrelude.Bool is Stdlib.Bool with additional Boolean functions; satisifes OrderedType.
module N0 : sig ... endType-specialized comparison; satisifes OrderedType.
module N1 : sig ... endType-specialized comparison; satisifes OrderedType.
module Int : sig ... endType-specialized operators and comparisons; satisifes ARITH.
module Float : sig ... endType-specialized operators and comparisons; satisifes ARITH.
module Pair : sig ... endUseful functions on 2-tuples.
(&&&) is Pair.cross.
( *** ) is Pair.diag.
module T3 : sig ... endUseful functions on 3-tuples.
module Interval : sig ... endInterval arithmetic over a type T: ARITH.
between is Interval.Int.between.
contains is Interval.Int.contains.
inbounds is Interval.Int.inbounds.
(r @:= x) conses x onto the list in ref r. N.B. conses not appends.
I'd prefer to use (::=) as the operator, but OCaml syntax doesn't allow it.
include module type of struct include Stdlib.Printf endmodule Exn : sig ... endFunctions for working with exceptions.
foldil is Interval.Int.foldil.
foldir is Interval.Int.foldir.
foreach is Interval.Int.foreach.
foldex is Exn.fold.
(whilst p f x) is a functional while-loop; it is (f ( ... (f (f x)))) while (p x) is true.
The quaint name is because while is an OCaml keyword.
Example: (whilst (function x::_ -> x <= 10 | [] -> false) tl) = (dropwhile (fun x -> x <= 10))
(until p f x) is a functional repeat-until-loop; it is whilst (not << p) f (f x).
(iff p consequent alternative x) is if p x then consequent x else alternative x.
Examples: (iff even cons (fun _ xs -> xs)) = (conswhen even)
(foldr (iff even cons (fun _ xs -> xs)) [] (1--20)) = [2; 4; 6; 8; 10; 12; 14; 16; 18; 20] (onlyif p f x) is (f x) iff (p x) and is x otherwise.
Example: (map (onlyif even (k 0)) (1--10)) = [1; 0; 3; 0; 5; 0; 7; 0; 9; 0]
module Seq : sig ... endFunctional Iterators
module Option : sig ... endOption monad and other useful functions on options.
val catch : ?this:exn -> ('a -> 'b) -> 'a -> 'b Option.tcatch is Option.catch
val some : 'a -> 'a Option.tsome is Option.some
none is Option.none
val something : 'a Option.t -> boolsomething is Option.something
val nothing : 'a Option.t -> boolnothing is Option.nothing
module Result : sig ... endResult (error) monad.
module Buffer : sig ... endAdditional Buffer functions.
withbuf2 is Buffer.withbuf2.
withbuf is Buffer.withbuf.
module Lists : sig ... endAdditional List functions and renamings.
List is opened.
include module type of struct include List endThis is Ocaml's standard List with the additional functions from Lists.
module type LIST = List.LISTinclude LISTinclude module type of struct include Lists endAdditional List functions and renamings.
We also include all the List functions that we want when we include Lists in Prelude.
(to_string ?left ?sep ?right f xs) returns a string representation of xs.
f is used for the string representation of each element of xs.
The representation of the list is inserted between ?left (default: "[") and ?right (default: "]"); each element of xs is separated by ?sep (default: "; ").
Example: (to_string string_of_int (1--10)) = "[1; 2; 3; 4; 5; 6; 7; 8; 9; 10]"
(init xs) is all the elements of xs except the last one; tail-recursive
(init xs) = (rev $ tl $ rev) (last xs) is the last element of xs; tail-recursive.
(last xs) = (hd (rev xs)) (unfoldr p f g x) builds a list (f x :: unfoldr p f g (g x)) from a seed value x until ((p x) = true). Not tail-recursive.
Example:
(unfoldr ((=) 0) id pred 10) = [10; 9; 8; 7; 6; 5; 4; 3; 2; 1](make n f) is [f 0; f 1; ...; f (n-1)], evaluated left to right. Tail-recursive.
Example: a list of 10 random integers in the range 0-99:
make 10 (fun _ -> Random.int 100) trappend is a tail-recursive List.append.
(prepend xs ys) prepends xs onto the front of ys and is another name for List.append.
(postpend xs ys) postpends xs onto the end of ys and is the same as (flip List.append).
(scanl f z list) is similar to foldl, but returns a list of successive reduced values from the left:
scanl (±) z [x1; x2; ...] = [z; z ± x1; (z ± x1) ± x2; ...] Invariant: (last (scanl f z xs)) = (foldl f z xs)
(eachpair f list) applies f to each consecutive pair of elements in list.
Example: (eachpair f [1;2;3;4]) = (f 1 2 :: f 2 3 :: f 3 4 :: [])
Invariants:
(eachpair f []) = [](eachpair f [x]) = []xs = [] || (len (eachpair f xs)) = (len xs - 1)(permutations xs) is the list of all permutations of xs; not tail-recursive. O(n!).
(upto m n) is the list of ints in the interval [m,n] (tail-recursive).
(upto 1 5) = [1; 2; 3; 4; 5].
(random ?size r ()) is a list of size (size ()) (default: < 100); the elements are given by (r ()).
(prefix pat subj) is true if pat is a prefix of subj and false otherwise.
Invariants:
(prefix [] xs) = true(prefix xs xs) = true(xs = [] || prefix (init xs) xs) = true(foldr f z xs) is (List.fold_right f xs z).
This order of parameters is much more useful in conjunction with the (|>)-operator.
foldl1 is foldl with no initial accumulator value, and thus must be applied to non-empty lists.
foldr1 is foldr with no initial accumulator value, and thus must be applied to non-empty lists.
(foldwise ?skip n f init xs) left-fold f across sequential non-overlapping n-wise subsequences of xs; tail-recursive.
For example, (foldwise 2) is a pairwise fold:
foldwise 2 (snocwith rev) [] (1--12) |> rev
= [[1; 2]; [3; 4]; [5; 6]; [7; 8]; [9; 10]; [11; 12]] f is given an accumulator and a sublist of length n. For efficiency, the sublists passed to f will be in the reverse of the order in which they occur in xs; f can reverse them if necessary.
Unless skip is true, f must be prepared to receive a final sublist of length less than n if the length of xs is not evenly divisible by n.
If (skip = true), only the initial (len xs - ((len xs) mod n)) elements of xs will be processed.
Invariants:
(foldwise n (snocwith rev) [] xs |> rev |> flatten) = xs(foldwise n ~skip:false f init (take (len xs - len xs mod n) xs)) = (foldwise n ~skip:true f init xs)Functions useful with foldl and foldr.
(conswith f) is (cons <? f) and also (fun x xs -> f x :: xs).
(conswhen p x xs) is (cons x xs) when p x = true and otherwise is xs.
foldr (conswhen Int.even) [] (1--10) = [2; 4; 6; 8; 10] (snocwith f) is (flip (conswith f)). Suitable for foldl.
(fun f -> foldl (snocwith f) [] $ rev) is a tail-recursive map.
(snocwhen p) is (flip (conswhen p)). Suitable for foldl.
(conjunction ps x) is the conjunction of the predicates in ps.
(disjunction ps x) is the disjunction of the predicates in ps.
(all p xs) is true if (p x) for all of the xs.
Invariant:
(all p xs) = (map p xs |> anded)(any p xs) is true if (p x) for any of the xs.
Invariant:
(any p xs) = (map p xs |> ored)(maximumBy compare xs) is the maximum of the xs according to compare.
Examples:
maximumBy compare (1--10) = 10 maximumBy compare ["zap";"foo"] = "zap" maximumBy compare ["ZAP";"foo"] = "foo" maximumBy AIString.compare ["ZAP";"foo"] = "ZAP" maximumBy AIString.compare ["zap";"foo"] = "zap" maximum is (maximumBy compare).
Examples:
maximum (1--10) = 10 maximum ["zap";"foo"] = "zap" maximum ["ZAP";"foo"] = "foo" (minimum ?compare xs) is the minimum of the xs. If provided, compare is used for comparison (default: polymorphic minimum via min).
Examples:
minimum (1--10) = 1 minimum ["zap";"foo"] = "foo" minimum ["ZAP";"foo"] = "ZAP" minimum ~compare:AIString.compare ["ZAP";"foo"] = "foo" minimum ~compare:AIString.compare ["zap";"foo"] = "foo" (break eq list) does control-break processing on the (typically sorted) list, grouping together consecutive subsequences of elements which are equal under eq.
N.B. For the sake of efficiency, the result is in reverse order, as are all the sublists. (List.rev_map rev) will restore order.
Example: this function:
(break (fun p x -> p.[0] = x.[0]))will group a sorted list of words into lists of words that begin with the same letter.
["copulatives"; "cumulative"; "deliverable"; "denial"; "drowning";
"folklorists"; "gradualism"; "lowliest"; "orangeade"; "oxen"]
|> break (fun p x -> p#!0 = x#!0) |> List.rev_map rev
= [["copulatives"; "cumulative"]; ["deliverable"; "denial"; "drowning"];
["folklorists"]; ["gradualism"]; ["lowliest"]; ["orangeade"; "oxen"]] (flatmap f) is a tail-recursive (map f $ concat).
(delete ?eq x xs) removes the first occurrence of x from xs; tail recursive.
(replace sub rep xs) replaces each occurrence of sub in xs with rep.
Examples:
(replace 1 10 (1--6)) = [10; 2; 3; 4; 5; 6](replace 10 20 (1--6)) = [1; 2; 3; 4; 5; 6]((1--6) |> map (flip (mod) 2) |> replace 0 2) = [1; 2; 1; 2; 1; 2](behead prefix list) is the remainder of list when the leading prefix is removed.
prefix must be an exact prefix of list for anything to be removed.
Invariants:
(behead [] xs) = xs(behead xs []) = [](behead xs xs) = [](behead (x::xs) xs) = xs(len (behead xs ys)) <= (len ys)(prefix xs ys) && (behead xs ys) <> ys(prefixes xs) is the list of all prefixes of xs.
(prefixes [1;2;3]) = [[]; [1]; [1; 2]; [1; 2; 3]] Invariants:
(prefixes xs) = (scanl snoc [] xs |> map rev)(prefixes xs |> map (flip prefix xs) |> anded) = true(prefixes xs |> hd) = [](suffixes xs) is the list of all suffixes of xs.
(suffixes [1;2;3]) = [[]; [3]; [2; 3]; [1; 2; 3]] Invariant: (suffixes xs |> hd) = []
(intersperse x xs) inserts x between the elements of xs.
Example: String.(explode "123456" |> intersperse ',' |> implode) = "1,2,3,4,5,6"
Invariants:
(intersperse x []) = [](intersperse x [y]) = [y](pad ?(left=false) ~def n xs) pads xs on the right (or on the left, if (left = true)) with enough instances of def such that the length of the result is at least n.
If you need the result list to be exactly of length n (never longer), use:
(take n $ pad ~def n)Invariant: (len (pad ~left ~def n xs) = max n (len xs))
(transpose ?def xss) is the transposition of the rows and columns of xss; tail recursive.
Unless def is provided, if any sublist is shorter than the first sublist, (Invalid_argument _) is raised. Otherwise, the resulting sublists will all be of length (len (nth xss 0)).
If def is provided, it serves as a default element that is appended as needed to bring all lists to the length of the longest list in xss; in this case, the "matrix" is guaranteed to be rectangular and no exception will be raised.
Examples:
transpose [1--3;4--6] = [[1; 4]; [2; 5]; [3; 6]]transpose [[1];[1;2]] = [[1; 1]]catch transpose [[1;2];[1]] = Nonetranspose ~def:0 [[1;2];[1]] = [[1; 1]; [2; 0]](evens xs) is all the elements of xs at even indexes.
evens [1; 3; 5] = [1; 5] evens ["a"; "b"; "c"] = ["a"; "c"] (odds xs) is all the elements of xs at odd indexes.
odds [0; 2; 4] = [2] odds ["a"; "b"; "c"] = ["b"] (splitat n xs) is (a,b) such that a is the length-n prefix of xs, and b is the remainder of the xs.
It is equivalent to (take n xs, drop n xs), but makes only one pass.
Invariant:
let a,b = splitat n xs in prefix a xs && (a @ b) = xsExamples:
splitat 3 [1;2;3;4;5] = [1;2;3], [4;5]splitat 1 [1;2;3] = [1], [2;3]splitat 3 [1;2;3] = [1;2;3], []splitat 4 [1;2;3] = [1;2;3], []splitat 0 [1;2;3] = [], [1;2;3]splitat ~-1 [1;2;3] = [], [1;2;3](everyother xs) is the list consisting of every other element of xs, starting with the first; O(n), 1-pass algorithm.
Invariants:
(len (everyother xs) = if even (len xs) then len xs / 2 else len xs / 2 + 1)(hd (everyother xs) = hd xs)(take n xs) is (splitat n >> fst).
Invariant: (take n xs) = (drop (len xs - n) (rev xs) |> rev)
(drop n xs) is (splitat n >> snd).
Invariant: (drop n xs) = (take (len xs - n) (rev xs) |> rev)
(takeall n list) returns the sequential sublists of length n in list.
If n <= 0, the empty list is returned.
Invariant:
(takeall n xs |> concat) = xsExample:
(takeall 3 (1--10)) = [[1; 2; 3]; [4; 5; 6]; [7; 8; 9]; [10]](splitwhile p xs) is (a,b) where a is the longest prefix of xs of elements that satisfy p and b is the remaining suffix..
Invariant:
splitwhile p xs |> fun (a,b) -> a@b = xs(takewhile p) is (splitwhile p >> fst)
Invariant:
(takewhile p xs @ dropwhile p xs) = xs(dropwhile p xs) is (splitwhile p >> snd).
Invariant:
(takewhile p xs @ dropwhile p xs) = xs(zip xs ys) takes two lists and returns a list of corresponding pairs; tail-recursive.
This is the same as List.combine, except that if one input list is short, excess elements of the longer list are discarded, rather than raising an exception.
Examples:
(zip (1--4) (5--8)) = [(1, 5); (2, 6); (3, 7); (4, 8)] (zip (1--2) (5--8)) = [(1, 5); (2, 6)] (zipwith f xs ys) is zip xs ys |> map (uncurry f).
(unzip xs) is List.split: it transforms a list of pairs into a list of first components and a list of second components.
Invariant:
(zip xs ys |> unzip) = (xs,ys) iff (len xs = len ys)module Assoc = List.AssocFunctions for working with association lists (alists).
See also on for a nice way to make comparison functions.
(sorted cmp list) is true iff (sort cmp list = list) and is false otherwise; O(n); tail-recursive, constant space.
sorted terminates at the first out-of-order value (if any), so it's much faster than (sort cmp list = list), especially for unsorted lists.
(uniq ?compare list) is the list of representative elements of the identical subsequences of xs; tail-recursive.
It's like sort_uniq but gives a different result for unsorted inputs.
Example:
(uniq [1;1;2;3;3;3;3;2;2;3;3]) = [1; 2; 3; 2; 3]Invariant:
(sort compare xs |> uniq ~compare) = (sort_uniq compare xs)(uniqc ?compare xs) is like (uniq xs) but each element is paired with the size of the original subsequence; tail-recursive.
Example:
(uniqc [1;1;2;3;3;3;3]) = [(2, 1); (1, 2); (4, 3)](index ?z list) is an alist whose keys are successive integers (starting from z (default: 0) and whose values are the elements of list; tail-recursive.
Examples:
(index (1--4)) = [(0, 1); (1, 2); (2, 3); (3, 4)](index ~z:1 (1--4)) = [(1, 1); (2, 2); (3, 3); (4, 4)](pos x xs) is the position (index) of the first x in xs, or -1 if x is NOT in xs; tail-recursive.
(project ?relaxed is xs) projects the elements of xs indexed by the indices in is; tail-recursive in the length of is.
The result is in the order of the occurrence of the indices in is.
If any index in is >= (len xs) or < 0, Not_found is raised, unless ~relaxed:true, in which case any bad indices are ignored, and the length of the result may be less than the length of is.
Examples:
(project [10] (1--20)) = [11](project [3;2;1;0] (1--4)) = [4; 3; 2; 1](project [4;4;4] (1--10)) = [5; 5; 5]Invariants:
((project ~relaxed:false is xs) |> len) = (len is)((project ~relaxed:false is []) && is <> []) = ⊥(project ~relaxed:true is []) = [](project [] xs) = []let xs = 1--n in (project (map pred xs) xs) = xs(project is xs) = (map (List.nth xs) is)Many of these functions are extremely inefficient compared to using Set. For use on lists guaranteed to be extremely short, or for playing in the top-level.
In most cases, in the spirit of "lists as sets", the order of elements is not preserved.
(nub ?compare xs) is the list xs with equal elements removed; tail-recursive; O(n log n).
Equality is determined by compare (default: Stdlib.compare).
The order of the elements in xs is not preserved.
Runs in constant heap space (in addition to the size of the result list) and logarithmic stack space.
nub (1--5 @ 1--3 @ 4--6) = [1; 2; 3; 4; 5; 6]
nub2 is nub but the order of the elements of the list is preserved; not tail-recursive; O(n^2).)
The 2 in nub2 is a reminder that it's O(n^2).
(union ?compare xs ys) returns the list union of the two lists (with no duplicates); not tail-recursive (length of the first argument).
Equality is determined by compare (default: Stdlib.compare).
The order of the elements in xs and ys is not preserved.
(union xs ys) = (xs @ ys |> nub)(intersect ?compare xs ys) returns the list intersection of the two lists; tail-recursive; O(n^2).
Equality is determined by compare (default: Stdlib.compare).
The order of the elements in xs and ys is not preserved.
(subset ?compare xs ys) is true if xs is a subset of ys; O(n^2).
Equality is determined by compare (default: Stdlib.compare).
The order of the elements in xs and ys is not preserved.
(diff ?compare xs ys): list difference: the elements of xs minus all of the elements in ys; tail-recursive, O(n^2).
Equality is determined by compare (default: Stdlib.compare).
The order of the elements in xs and ys is not preserved.
(cartesian_product xss) is the Cartesian product of the list of lists xss; not tail-recursive.
Deck of cards:
(cartesian_product [["♠";"♥";"♦";"♣"];("A"::map string_of_int (2--10)@["J";"Q";"K"])]) (powerset xs) is the list of all sublists of xs, including [] and xs itself; not tail-recursive.
(combinations n lst) is the list of all subset lists of lst consisting of n elements; not tail-recursive.
These functions can be used to hand-translate Haskell-style list comprehensions. For example:
[ (n,c) | n <- [1,2], c <- ['a','b'] ] = [(1, 'a'); (1, 'b'); (2, 'a'); (2, 'b')]This can be expressed as:
[1;2] >>= fun n -> ['a';'b'] >>= fun c -> return (n,c) module Ops = List.OpsInfix and prefix operators.
assocs is List.Assoc.assocs.
(--) is List.Ops.(--).
module List1 : sig ... endNon-Empty Lists
module Random : sig ... endAdditional random functions.
shuffle is Random.shuffle.
choose is Random.choose.
module Hashtbl : sig ... endThis is Ocaml's standard Hashtbl with some additional functions.
module Array : sig ... endOCaml's Array module with some extra functions.
module Ia = Iamodule A1 = A1OCaml's Array module with 1-based indexing.
module Gen : sig ... endTrivial generators ("lazy" sequences / streams). NOT thread-safe.
module Chars : sig ... endAdditional char functions.
module Format : sig ... endThis is Ocaml's standard Format with some additional functions and values.
module Strings : sig ... endAdditional string functions.
module String : sig ... endThis is Ocaml's standard String with the additional functions from Strings and with Strings.Ops opened.
split is Strings.split
join is Strings.join
(#!) is Strings.(#!).
(#.) is Strings.(#.).
module AIString : sig ... endCase-insensitive ASCII strings.
module Show : sig ... endAlternate access to Type-Specific string conversions.
module Print : sig ... endAlternate access to type-specific print functions.
module type VECTOR = sig ... endFast functional arrays.
module Map : sig ... endMap.Make (M) is the module returned by OCaml's Map.Make (M) with some additional functions.
module Set : sig ... endSet.Make (M) is the module returned by Stdlib.Set.Make (M) with some additional functions.
module Multiset : sig ... endMultiset.Make (Ord) is a set of Ord.t's with repetition.
module type STACK = sig ... endPurely functional stacks.
module Queue : sig ... endPurely functional FIFO queues.
module Rose : sig ... endN-ary (Rose) trees.
module Leftist : sig ... endA leftist heap; can be a min-heap or a max-heap.
val syserrors :
?exit:bool ->
?message:(?ff:Format.formatter -> ?prefix:string -> string -> unit) ->
('a -> unit) ->
'a ->
unit(syserrors ?exit ?message f x) is (Sys.catch_break true; f x); any Sys_error or Unix.Unix_error exceptions are printed "more attractively" (via Exn.to_string) to stderr.
We call (Sys.catch_break true) because otherwise SIGINT (the signal sent by a control-C) terminates the program without allowing finalizers to finalize!
If (~exit = true), the program terminates via Stdlib.exit; otherwise, the program does not exit at all -- false is good for testing in the top-level (default value for ~exit: true).
Error messages are printed via ~message (default: Message.message). ~message will be called with various exit statuses for the following exceptions as follows:
Sys.Break: ~exit:1Failed_prerequisite: ~exit:3~exit:125"More attractively" means, for example, that an attempt to open a non-existent file would look like: /etc/passwdx: No such file or directory
rather than the usual OCaml:
Fatal error: exception Sys_error("/etc/passwdx: No such file or directory")
Raised by primitive operation at unknown location
Called from unknown location Typical usage:
let main () = iter (readfile $ write stdout) argv
let () = syserrors main ()val version_of_string : string -> int Option.t listversion_of_string converts common version number strings to values that can be easily compared.
N.B. due to the variation in version number formats, one can't typically expect to meaningfully compare the versions of two different programs, but fortunately one can typically compare newer and older versions of the same program.
Examples:
(version_of_string "1.1.11+50+gb685338-1" = [Some 1; Some 1; Some 11; Some 50; None; Some 1])(on (<) version_of_string "1.1.11+50+gb685338-1" "1.2.11+50+gb68531238-1")module File : sig ... endAdditional functions on files and filenames.
(~~) is File.squiggle.
withcd is File.withcd.
val eol : eol -> string(eol e) returns the string corresponding to the line-ending.
Avoiding file descriptor leaks.
N.B. within and without do not perform ~-expansion on filenames; in typical use where filenames come from the command-line, this is unnecessary because the shell does the ~-expansion before your program sees the filename.
If you want to do ~-expansion yourself, just transform e.g.:
(within read) -> (within read << File.squiggle)
iflags are the default flags passed to open_in_gen by within (default: [Open_rdonly]).
oflags are the default flags passed to open_out_gen by without (default: [Open_creat;Open_wronly;Open_trunc]).
val within :
?dash:string option ->
?iflags:Stdlib.open_flag list ->
(Stdlib.in_channel -> 'a) ->
string ->
'a(within ?dash ?iflags f file) opens file for input and returns (f c) where c is the in_channel; c is guaranteed to be closed when within returns, even if f raises an exception (which is re-raised).
iflags are passed to open_in_gen (default: iflags).
dash specifies a filename that is interpreted as stdin (default: Some dash); use ~dash:None to avoid any such interpretation.
val without :
?dash:string option ->
?oflags:Stdlib.open_flag list ->
?perm:int ->
(Stdlib.out_channel -> 'a) ->
string ->
'a(without ?dash ?oflags ?perm f file) opens file for output and returns (f c) where c is the out_channel; c is guaranteed to be closed when without returns, even if f raises an exception (which is re-raised).
dash specifies a filename that is interpreted as stdout (default: Some dash); use ~dash:None to avoid any such interpretation.
oflags are passed to open_out_gen (default: oflags).
perm specifies the permissions used when a file is created (default: 0o666); these are subject to your umask in the usual manner.
val withinout :
?dash:string option ->
?iflags:Stdlib.open_flag list ->
?oflags:Stdlib.open_flag list ->
?perm:int ->
(Stdlib.in_channel -> Stdlib.out_channel -> 'a) ->
infile:string ->
outfile:string ->
'a(withinout ?dash ?iflags ?oflags ?perm f ~infile ~outfile) opens infile for input and outfile for output and returns (f inc outc) where inc is the in_channel and outc is the out_channel; both channels are guaranteed to be closed when withinout returns, even if f raises an exception (which is re-raised).
dash, perm, and oflags are as for without, and iflags is as for within.
val withtempfile :
?tmpdir:string ->
?oflags:Stdlib.open_flag list ->
?perm:int ->
?prefix:string ->
?suffix:string ->
(string -> Stdlib.out_channel -> 'a) ->
'a(withtempfile ?tmpdir ?oflags ?perm ?prefix ?suffix f) calls f with a secure, writable temporary file; when f returns, the temp file is guaranteed to be removed.
f is called with two parameters, the name of the temp file, and an output channel open on the temp file. f can close and reopen the file (say, for reading) if it likes.
(read ?bufsize c) reads the entire contents of in_channel c and returns the result as a string.
bufsize is the size of the input buffer used (default: blocksize).
val readblock : ?buf:bytes -> ?size:int -> Stdlib.in_channel -> string Option.t(readblock ?buf ?size c) returns (Some b) where b is the next block of size (or fewer) characters from channel c, or else None upon end of file.
If you are calling readblock repeatedly, as is typical, it is more efficient to pass ~buf, a Bytes.t of size >= size (this minimizes allocations).
size is the size of the input buffer used (default: Bytes.length buf or else blocksize).
(readfile ?dash ?bufsize fn) is (within ?dash (read ?bufsize) fn).
val readline' : ?elide:bool -> ?eol:eol -> Stdlib.in_channel -> string(readline' ?elide ?buf ?eol chan) is a readline that retains the EOL character(s).
Rationale:
(foldlines ~readline:readline (fun () -> print_endline) ()) nor (foldlines ~readline:readline (fun () -> print_string) ()) is guaranteed to make an exact copy of their input, whereas (foldlines ~readline:readline' (fun () -> print_string) ()) is.So: (writefile ~fn:"/tmp/foo" "foo\n"; within readline' "/tmp/foo" = "foo\n")
whereas: (writefile ~fn:"/tmp/foo" "foo\n"; within readline "/tmp/foo" = "foo")
~eol determines the EOL character(s). The default for ~eol is LF. In CRLF mode, isolated '\r' and '\n' do not terminate the line, and are returned "in the middle" of the line.
~elide:true causes the EOL character(s) to be trimmed from the end of the line, like readline always does for '\n'. The default value for ~elide is false.
Mnemonic: the ' in readline' stands for the presence of the EOL.
(readlines ?readline c) is a list of all the lines on the in_channel c; end-of-line characters will be present or absent depending the value you choose for ~readline; the default trims EOLs.
~readline is the function that reads each line; suitable candidates include input_line (the default), readline, and readline'.
(foldchars f acc c) folds f over the chars on in_channel c.
(foldchars snoc [] >> rev >> String.implode = readfile), but would be considerably less efficient than readfile.
val foldlines :
?readline:(Stdlib.in_channel -> string) ->
('a -> string -> 'a) ->
'a ->
Stdlib.in_channel ->
'a(foldlines ?readline f acc c) folds f over the lines on in_channel c.
?readline is as for readlines.
(foldlines (snocwith f) [] >> rev) = maplines f val maplines :
?readline:(Stdlib.in_channel -> string) ->
(string -> 'a) ->
Stdlib.in_channel ->
'a list(maplines ?readline f c) maps f across all the lines on in_channel c, returning the list of results.
?readline is as for readlines.
val iterlines :
?readline:(Stdlib.in_channel -> string) ->
(string -> unit) ->
Stdlib.in_channel ->
unit(iterlines1 ?readline f c) applies f to each of the lines on in_channel c, for side-effect.
?readline is as for readlines.
val chars_of_chan : Stdlib.in_channel -> char Seq.t(chars_of_chan chan) is the sequence of characters from chan.
val lines_of_chan : Stdlib.in_channel -> string Seq.t(lines_of_chan chan) is the sequence of lines from chan.
val writeline : ?eol:eol -> Stdlib.out_channel -> string -> unit(writeline ?eol chan s) is (output_string chan s) followed by the line-ending ~eol (default: LF).
val writelines : ?eol:eol -> Stdlib.out_channel -> string list -> unit(writelines ?eol chan) is (iter (writeline ?eol chan))
val writefile :
?dash:string option ->
?oflags:Stdlib.open_flag list ->
?perm:int ->
fn:string ->
string ->
unit(writefile ?dash ?oflags ?perm ~fn s) writes s to file fn, passing the optional parameters to without.
(copyto ?size oc ic) copies the contents of the input channel ic to the output channel oc one size-block at a time.
?size defaults to blocksize.
Examples:
(within (copyto stdout) "/etc/passwd")"infile" to "outfile": (without (fun oc -> within (copyto oc) "infile") "outfile")module Interact : sig ... endSimple interaction with a human at a terminal.
module Units : sig ... endModules for converting and displaying units.
Including a pure OCaml implementation of strftime(3).
module Time : sig ... endmodule Message : sig ... endEasy to use message functions for warnings, errors, and verbosity, with a lot of fiddly options.
module Log : sig ... endSimple functions for log files with timestamps, log rotation, etc.
module Email : sig ... endParse (partially) Email mboxes and messages.
module Refer : sig ... endParse and generate Extended Refer databases.
module Macro : sig ... endSimple macro expansion in strings.
module ISN : sig ... endmodule Unix : sig ... endAdditional Unix functions.
module Prereq : sig ... endFunctions to test for the availability of external prerequisite commands.
Extensions to modules we don't want to depend upon.
Extended.Benchmark: additional functions for Christophe Troestler's Benchmark module.Extended.Parmap: additional functions for Parmap.Extended.Re: additional regular expression functions for Re.Extended.Uri: additional Uri functions.Extended.Xmlm: additional XML functions for Daniel Bünzli's Xmlm.module Extended : sig ... endExtensions.
Here's a quick example to give you an idea of what things looks like. This program isn't intended to be necessarily the most readable, or the most terse, but rather to illustrate as many Prelude features as possible in a small amount of code.
I've added line numbers; see below for a line-by-line explanation.
This program reads the file named as its first command-line argument, or, if there is no such argument, the file /usr/share/dict/words as a default. It splits each line into whitespace-separated words, and adds each word to a multiset (bag) which gathers together strings case-insensitively. Then it prints, in case-insensitive alphabetical order, all the words that have more than one spelling. The output looks something like this:
2: [blackberry's; BlackBerry's]
2: [cordilleras; Cordilleras]
2: [debs; Debs]
2: [dot's; Dot's]
3: [ms; Ms; MS]
3: [teleprompter; TelePrompter; TelePrompTer]A brief error message (no stack trace) is printed if there's a problem opening a named file, in which case the program exits with status 125. The error message might look like this:
1 open Prelude
2 module MS = Multiset.Make (AIString)
3 let main () =
4 argv
5 |> head
6 |> Option.default "/usr/share/dict/words"
7 |> within (foldlines (fun ms -> split >> foldr MS.add ms) MS.empty)
8 |> flip (MS.fold (conswhen (len >> gt 1))) []
9 |> rev
10 |> iter (fun ws -> to_string id ws |> printf "%d: %s\n" (len ws))
11 let () = syserrors main ()Multiset to group together equivalent strings; the AIString module implements OrderedType for ASCII case-Insensitive strings.string option).None (because argv is empty) replace it with "/usr/share/dict/words".within (...) to be opened, and passed as an in_channel to the function -- and guaranteed to be closed when the function terminates, even if an exception was raised. The function (see below) returns a Multiset.S.t of all the words in the file.string list list. Each sublist is the different spellings of a word.main, catching any exceptions (we only expect I/O errors) and printing them attractively, with no stack trace.foldlines (fun ms -> split >> foldr MS.add ms) MS.emptyThis function adds all the words of the input to our multiset. foldlines folds a flipped-cons-like function over the lines of an in_channel. MS.empty is our initial accumulator. Our function uses split to split the line into words (a string list) and we fold over that list with foldr, which is a synonym for List.fold_right. MS.add adds a word to our multiset. (>>) is left-to-right function composition.
flip (MS.fold (conswhen (len >> gt 1))) []This function folds over the equivalence-classes of word-spellings that make up our multiset. The multiset stores each equivalence-class as a list of strings that are equal according to AIString.compare.
(len >> gt 1) is a predicate that's true iff a word-list has length greater than 1 -- in other words, if the word has multiple spellings. len is List.length and gt is (flip (>)).
conswhen is a (::) that only conses when it's predicate is true. So (MS.fold (conswhen (len >> gt 1))) is a function that takes a multiset and an initial accumulator (the empty list []) and conses an equivalence-class onto the accumulator if it has multiple spellings. The order of that function's two parameters is awkward so we flip them (and avoid writing a lambda). The result of this whole function is a list of lists: a list of non-trivial equivalence-classes.
iter (fun ws -> to_string id ws |> printf "%d: %s\n" (len ws))Finally we iterate over the list of equivalence-classes and print each list on a line, prefixed by its length. iter is List.iter. Prelude does (include Printf) since its functions are so useful and have unambiguous names. Since Prelude does (include Prelude.Lists), to_string is Lists.to_string. Prelude defines a flexible to_string function for all its data types and for most of the OCaml base types. to_string takes a function to convert a list element to a string -- since we have a list of strings, we just use id, the identity function. Lists.to_string takes a number of optional parameters but it's default is to format a list the way the top-level would.