More comments in stdlib (#237)

This commit is contained in:
Radosław Rowicki 2020-02-25 12:56:51 +01:00 committed by GitHub
parent bd7ed2ef8c
commit d7fa4d65ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 139 additions and 28 deletions

View File

@ -7,7 +7,10 @@ namespace Frac =
datatype frac = Pos(int, int) | Zero | Neg(int, int) datatype frac = Pos(int, int) | Zero | Neg(int, int)
// Checks if internal representation is correct. Numerator and denominator must be positive. /** Checks if the internal representation is correct.
* Numerator and denominator must be positive.
* Exposed for debug purposes
*/
function is_sane(f : frac) : bool = switch(f) function is_sane(f : frac) : bool = switch(f)
Pos(n, d) => n > 0 && d > 0 Pos(n, d) => n > 0 && d > 0
Zero => true Zero => true
@ -38,7 +41,8 @@ namespace Frac =
Neg(n, d) => String.concat("-", to_str(Pos(n, d))) Neg(n, d) => String.concat("-", to_str(Pos(n, d)))
Zero => "0" Zero => "0"
// Reduce fraction to normal form /** Reduce fraction to normal form
*/
function simplify(f : frac) : frac = function simplify(f : frac) : frac =
switch(f) switch(f)
Neg(n, d) => Neg(n, d) =>
@ -49,6 +53,8 @@ namespace Frac =
let cd = gcd(n, d) let cd = gcd(n, d)
Pos(n / cd, d / cd) Pos(n / cd, d / cd)
/** Integer to rational division
*/
function make_frac(n : int, d : int) : frac = function make_frac(n : int, d : int) : frac =
if (d == 0) abort("Division by zero") if (d == 0) abort("Division by zero")
elif (n == 0) Zero elif (n == 0) Zero
@ -111,7 +117,9 @@ namespace Frac =
Zero => 0 Zero => 0
Neg(n, d) => -(n + d - 1) / d Neg(n, d) => -(n + d - 1) / d
// Round towards nearest integer. If two integers are in the same distance, choose the even one. /** Round towards nearest integer. If two integers are in the same
* distance, choose the even one.
*/
function round(f : frac) : int = function round(f : frac) : int =
let fl = floor(f) let fl = floor(f)
let cl = ceil(f) let cl = ceil(f)
@ -146,6 +154,8 @@ namespace Frac =
function div(a : frac, b : frac) : frac = mul(a, inv(b)) function div(a : frac, b : frac) : frac = mul(a, inv(b))
/** `b` to the power of `e`
*/
function int_exp(b : frac, e : int) : frac = function int_exp(b : frac, e : int) : frac =
if (sign(b) == 0 && e == 0) abort("Zero to the zero exponentation") if (sign(b) == 0 && e == 0) abort("Zero to the zero exponentation")
elif (e < 0) inv(int_exp_(b, -e)) elif (e < 0) inv(int_exp_(b, -e))
@ -158,8 +168,9 @@ namespace Frac =
if (e mod 2 == 1) mul(mul(half, half), b) if (e mod 2 == 1) mul(mul(half, half), b)
else mul(half, half) else mul(half, half)
// Reduces the fraction's in-memory size by dividing its components by two until the /** Reduces the fraction's in-memory size by dividing its components by two until the
// the error is bigger than `loss` value * the error is bigger than `loss` value
*/
function optimize(f : frac, loss : frac) : frac = function optimize(f : frac, loss : frac) : frac =
require(geq(loss, Zero), "negative loss optimize") require(geq(loss, Zero), "negative loss optimize")
let s = sign(f) let s = sign(f)

View File

@ -12,35 +12,66 @@ namespace Func =
function rapply(x : 'a, f : 'a => 'b) : 'b = f(x) function rapply(x : 'a, f : 'a => 'b) : 'b = f(x)
/* The Z combinator - replacement for local and anonymous recursion. /** The Z combinator - replacement for local and anonymous recursion.
*/ */
function recur(f : ('arg => 'res, 'arg) => 'res) : 'arg => 'res = function recur(f : ('arg => 'res, 'arg) => 'res) : 'arg => 'res =
(x) => f(recur(f), x) (x) => f(recur(f), x)
/** n-times composition with itself
*/
function iter(n : int, f : 'a => 'a) : 'a => 'a = iter_(n, f, (x) => x) function iter(n : int, f : 'a => 'a) : 'a => 'a = iter_(n, f, (x) => x)
private function iter_(n : int, f : 'a => 'a, acc : 'a => 'a) : 'a => 'a = private function iter_(n : int, f : 'a => 'a, acc : 'a => 'a) : 'a => 'a =
if(n == 0) acc if(n == 0) acc
elif(n == 1) comp(f, acc) elif(n == 1) comp(f, acc)
else iter_(n / 2, comp(f, f), if(n mod 2 == 0) acc else comp(f, acc)) else iter_(n / 2, comp(f, f), if(n mod 2 == 0) acc else comp(f, acc))
function curry2(f : ('a, 'b) => 'c) : 'a => ('b => 'c) = /** Turns an ugly, bad and disgusting arity-n function into
* a beautiful and sweet function taking the first argument
* and returning a function watiting for the remaining ones
* in the same manner
*/
function curry2(f : ('a, 'b) => 'x) : 'a => ('b => 'x) =
(x) => (y) => f(x, y) (x) => (y) => f(x, y)
function curry3(f : ('a, 'b, 'c) => 'd) : 'a => ('b => ('c => 'd)) = function curry3(f : ('a, 'b, 'c) => 'x) : 'a => ('b => ('c => 'x)) =
(x) => (y) => (z) => f(x, y, z) (x) => (y) => (z) => f(x, y, z)
function curry4(f : ('a, 'b, 'c, 'd) => 'x) : 'a => ('b => ('c => ('d => 'x))) =
(x) => (y) => (z) => (w) => f(x, y, z, w)
function curry5(f : ('a, 'b, 'c, 'd, 'e) => 'x) : 'a => ('b => ('c => ('d => ('e => 'x)))) =
(x) => (y) => (z) => (w) => (q) => f(x, y, z, w, q)
function uncurry2(f : 'a => ('b => 'c)) : ('a, 'b) => 'c = /** Opposite of curry. Gross
*/
function uncurry2(f : 'a => ('b => 'x)) : ('a, 'b) => 'x =
(x, y) => f(x)(y) (x, y) => f(x)(y)
function uncurry3(f : 'a => ('b => ('c => 'd))) : ('a, 'b, 'c) => 'd = function uncurry3(f : 'a => ('b => ('c => 'x))) : ('a, 'b, 'c) => 'x =
(x, y, z) => f(x)(y)(z) (x, y, z) => f(x)(y)(z)
function uncurry4(f : 'a => ('b => ('c => ('d => 'x)))) : ('a, 'b, 'c, 'd) => 'x =
(x, y, z, w) => f(x)(y)(z)(w)
function uncurry5(f : 'a => ('b => ('c => ('d => ('e => 'x))))) : ('a, 'b, 'c, 'd, 'e) => 'x =
(x, y, z, w, q) => f(x)(y)(z)(w)(q)
function tuplify2(f : ('a, 'b) => 'c) : (('a * 'b)) => 'c = /** Turns an arity-n function into a function taking n-tuple
*/
function tuplify2(f : ('a, 'b) => 'x) : (('a * 'b)) => 'x =
(t) => switch(t) (t) => switch(t)
(x, y) => f(x, y) (x, y) => f(x, y)
function tuplify3(f : ('a, 'b, 'c) => 'd) : 'a * 'b * 'c => 'd = function tuplify3(f : ('a, 'b, 'c) => 'x) : 'a * 'b * 'c => 'x =
(t) => switch(t) (t) => switch(t)
(x, y, z) => f(x, y, z) (x, y, z) => f(x, y, z)
function tuplify4(f : ('a, 'b, 'c, 'd) => 'x) : 'a * 'b * 'c * 'd => 'x =
(t) => switch(t)
(x, y, z, w) => f(x, y, z, w)
function tuplify5(f : ('a, 'b, 'c, 'd, 'e) => 'x) : 'a * 'b * 'c * 'd * 'e => 'x =
(t) => switch(t)
(x, y, z, w, q) => f(x, y, z, w, q)
function untuplify2(f : 'a * 'b => 'c) : ('a, 'b) => 'c = /** Opposite of tuplify
*/
function untuplify2(f : 'a * 'b => 'x) : ('a, 'b) => 'x =
(x, y) => f((x, y)) (x, y) => f((x, y))
function untuplify3(f : 'a * 'b * 'c => 'd) : ('a, 'b, 'c) => 'd = function untuplify3(f : 'a * 'b * 'c => 'x) : ('a, 'b, 'c) => 'x =
(x, y, z) => f((x, y, z)) (x, y, z) => f((x, y, z))
function untuplify4(f : 'a * 'b * 'c * 'd => 'x) : ('a, 'b, 'c, 'd) => 'x =
(x, y, z, w) => f((x, y, z, w))
function untuplify5(f : 'a * 'b * 'c * 'd * 'e => 'x) : ('a, 'b, 'c, 'd, 'e) => 'x =
(x, y, z, w, q) => f((x, y, z, w, q))

View File

@ -19,10 +19,15 @@ namespace List =
[x] => Some(x) [x] => Some(x)
_::t => last(t) _::t => last(t)
/** Finds first element of `l` fulfilling predicate `p` as `Some` or `None`
* if no such element exists.
*/
function find(p : 'a => bool, l : list('a)) : option('a) = switch(l) function find(p : 'a => bool, l : list('a)) : option('a) = switch(l)
[] => None [] => None
h::t => if(p(h)) Some(h) else find(p, t) h::t => if(p(h)) Some(h) else find(p, t)
/** Returns list of all indices of elements from `l` that fulfill the predicate `p`.
*/
function find_indices(p : 'a => bool, l : list('a)) : list(int) = find_indices_(p, l, 0, []) function find_indices(p : 'a => bool, l : list('a)) : list(int) = find_indices_(p, l, 0, [])
private function find_indices_( p : 'a => bool private function find_indices_( p : 'a => bool
, l : list('a) , l : list('a)
@ -50,14 +55,22 @@ namespace List =
_::t => length_(t, acc + 1) _::t => length_(t, acc + 1)
/** Creates an ascending sequence of all integer numbers
* between `a` and `b` (including `a` and `b`)
*/
function from_to(a : int, b : int) : list(int) = [a..b] function from_to(a : int, b : int) : list(int) = [a..b]
/** Creates an ascending sequence of integer numbers betweeen
* `a` and `b` jumping by given `step`. Includes `a` and takes
* `b` only if `(b - a) mod step == 0`. `step` should be bigger than 0.
*/
function from_to_step(a : int, b : int, s : int) : list(int) = from_to_step_(a, b, s, []) function from_to_step(a : int, b : int, s : int) : list(int) = from_to_step_(a, b, s, [])
private function from_to_step_(a, b, s, acc) = private function from_to_step_(a, b, s, acc) =
if (a > b) reverse(acc) else from_to_step_(a + s, b, s, a :: acc) if (a > b) reverse(acc) else from_to_step_(a + s, b, s, a :: acc)
/* Unsafe. Replaces `n`th element of `l` with `e`. Crashes on over/underflow */ /** Unsafe. Replaces `n`th element of `l` with `e`. Crashes on over/underflow
*/
function replace_at(n : int, e : 'a, l : list('a)) : list('a) = function replace_at(n : int, e : 'a, l : list('a)) : list('a) =
if(n<0) abort("insert_at underflow") else replace_at_(n, e, l, []) if(n<0) abort("insert_at underflow") else replace_at_(n, e, l, [])
private function replace_at_(n : int, e : 'a, l : list('a), acc : list('a)) : list('a) = private function replace_at_(n : int, e : 'a, l : list('a), acc : list('a)) : list('a) =
@ -66,7 +79,8 @@ namespace List =
h::t => if (n == 0) reverse(e::acc) ++ t h::t => if (n == 0) reverse(e::acc) ++ t
else replace_at_(n-1, e, t, h::acc) else replace_at_(n-1, e, t, h::acc)
/* Unsafe. Adds `e` to `l` to be its `n`th element. Crashes on over/underflow */ /** Unsafe. Adds `e` to `l` to be its `n`th element. Crashes on over/underflow
*/
function insert_at(n : int, e : 'a, l : list('a)) : list('a) = function insert_at(n : int, e : 'a, l : list('a)) : list('a) =
if(n<0) abort("insert_at underflow") else insert_at_(n, e, l, []) if(n<0) abort("insert_at underflow") else insert_at_(n, e, l, [])
private function insert_at_(n : int, e : 'a, l : list('a), acc : list('a)) : list('a) = private function insert_at_(n : int, e : 'a, l : list('a), acc : list('a)) : list('a) =
@ -75,6 +89,9 @@ namespace List =
[] => abort("insert_at overflow") [] => abort("insert_at overflow")
h::t => insert_at_(n-1, e, t, h::acc) h::t => insert_at_(n-1, e, t, h::acc)
/** Assuming that cmp represents `<` comparison, inserts `x` before
* the first element in the list `l` which is greater than it
*/
function insert_by(cmp : (('a, 'a) => bool), x : 'a, l : list('a)) : list('a) = function insert_by(cmp : (('a, 'a) => bool), x : 'a, l : list('a)) : list('a) =
insert_by_(cmp, x, l, []) insert_by_(cmp, x, l, [])
private function insert_by_(cmp : (('a, 'a) => bool), x : 'a, l : list('a), acc : list('a)) : list('a) = private function insert_by_(cmp : (('a, 'a) => bool), x : 'a, l : list('a), acc : list('a)) : list('a) =
@ -109,6 +126,8 @@ namespace List =
[] => reverse(acc) [] => reverse(acc)
h::t => map_(f, t, f(h)::acc) h::t => map_(f, t, f(h)::acc)
/** Effectively composition of `map` and `flatten`
*/
function flat_map(f : 'a => list('b), l : list('a)) : list('b) = function flat_map(f : 'a => list('b), l : list('a)) : list('b) =
ListInternal.flat_map(f, l) ListInternal.flat_map(f, l)
@ -117,7 +136,8 @@ namespace List =
[] => reverse(acc) [] => reverse(acc)
h::t => filter_(p, t, if(p(h)) h::acc else acc) h::t => filter_(p, t, if(p(h)) h::acc else acc)
/* Take `n` first elements */ /** Take `n` first elements
*/
function take(n : int, l : list('a)) : list('a) = function take(n : int, l : list('a)) : list('a) =
if(n < 0) abort("Take negative number of elements") else take_(n, l, []) if(n < 0) abort("Take negative number of elements") else take_(n, l, [])
private function take_(n : int, l : list('a), acc : list('a)) : list('a) = private function take_(n : int, l : list('a), acc : list('a)) : list('a) =
@ -126,7 +146,8 @@ namespace List =
[] => reverse(acc) [] => reverse(acc)
h::t => take_(n-1, t, h::acc) h::t => take_(n-1, t, h::acc)
/* Drop `n` first elements */ /** Drop `n` first elements
*/
function drop(n : int, l : list('a)) : list('a) = function drop(n : int, l : list('a)) : list('a) =
if(n < 0) abort("Drop negative number of elements") if(n < 0) abort("Drop negative number of elements")
elif (n == 0) l elif (n == 0) l
@ -134,18 +155,23 @@ namespace List =
[] => [] [] => []
h::t => drop(n-1, t) h::t => drop(n-1, t)
/* Get the longest prefix of a list in which every element matches predicate `p` */ /** Get the longest prefix of a list in which every element
* matches predicate `p`
*/
function take_while(p : 'a => bool, l : list('a)) : list('a) = take_while_(p, l, []) function take_while(p : 'a => bool, l : list('a)) : list('a) = take_while_(p, l, [])
private function take_while_(p : 'a => bool, l : list('a), acc : list('a)) : list('a) = switch(l) private function take_while_(p : 'a => bool, l : list('a), acc : list('a)) : list('a) = switch(l)
[] => reverse(acc) [] => reverse(acc)
h::t => if(p(h)) take_while_(p, t, h::acc) else reverse(acc) h::t => if(p(h)) take_while_(p, t, h::acc) else reverse(acc)
/* Drop elements from `l` until `p` holds */ /** Drop elements from `l` until `p` holds
*/
function drop_while(p : 'a => bool, l : list('a)) : list('a) = switch(l) function drop_while(p : 'a => bool, l : list('a)) : list('a) = switch(l)
[] => [] [] => []
h::t => if(p(h)) drop_while(p, t) else l h::t => if(p(h)) drop_while(p, t) else l
/* Splits list into two lists of elements that respectively match and don't match predicate `p` */ /** Splits list into two lists of elements that respectively
* match and don't match predicate `p`
*/
function partition(p : 'a => bool, l : list('a)) : (list('a) * list('a)) = partition_(p, l, [], []) function partition(p : 'a => bool, l : list('a)) : (list('a) * list('a)) = partition_(p, l, [], [])
private function partition_( p : 'a => bool private function partition_( p : 'a => bool
, l : list('a) , l : list('a)
@ -155,7 +181,8 @@ namespace List =
[] => (reverse(acc_t), reverse(acc_f)) [] => (reverse(acc_t), reverse(acc_f))
h::t => if(p(h)) partition_(p, t, h::acc_t, acc_f) else partition_(p, t, acc_t, h::acc_f) h::t => if(p(h)) partition_(p, t, h::acc_t, acc_f) else partition_(p, t, acc_t, h::acc_f)
/** Flattens list of lists into a single list
*/
function flatten(ll : list(list('a))) : list('a) = foldr((l1, l2) => l1 ++ l2, [], ll) function flatten(ll : list(list('a))) : list('a) = foldr((l1, l2) => l1 ++ l2, [], ll)
function all(p : 'a => bool, l : list('a)) : bool = switch(l) function all(p : 'a => bool, l : list('a)) : bool = switch(l)
@ -171,7 +198,9 @@ namespace List =
function product(l : list(int)) : int = foldl((a, b) => a * b, 1, l) function product(l : list(int)) : int = foldl((a, b) => a * b, 1, l)
/* Zips two list by applying bimapping function on respective elements. Drops longer tail. */ /** Zips two list by applying bimapping function on respective elements.
* Drops longer tail.
*/
function zip_with(f : ('a, 'b) => 'c, l1 : list('a), l2 : list('b)) : list('c) = zip_with_(f, l1, l2, []) function zip_with(f : ('a, 'b) => 'c, l1 : list('a), l2 : list('b)) : list('c) = zip_with_(f, l1, l2, [])
private function zip_with_( f : ('a, 'b) => 'c private function zip_with_( f : ('a, 'b) => 'c
, l1 : list('a) , l1 : list('a)
@ -181,7 +210,8 @@ namespace List =
(h1::t1, h2::t2) => zip_with_(f, t1, t2, f(h1, h2)::acc) (h1::t1, h2::t2) => zip_with_(f, t1, t2, f(h1, h2)::acc)
_ => reverse(acc) _ => reverse(acc)
/* Zips two lists into list of pairs. Drops longer tail. */ /** Zips two lists into list of pairs. Drops longer tail.
*/
function zip(l1 : list('a), l2 : list('b)) : list('a * 'b) = zip_with((a, b) => (a, b), l1, l2) function zip(l1 : list('a), l2 : list('b)) : list('a * 'b) = zip_with((a, b) => (a, b), l1, l2)
function unzip(l : list('a * 'b)) : list('a) * list('b) = unzip_(l, [], []) function unzip(l : list('a * 'b)) : list('a) * list('b) = unzip_(l, [], [])
@ -199,7 +229,8 @@ namespace List =
h::t => switch (partition((x) => lesser_cmp(x, h), t)) h::t => switch (partition((x) => lesser_cmp(x, h), t))
(lesser, bigger) => sort(lesser_cmp, lesser) ++ h::sort(lesser_cmp, bigger) (lesser, bigger) => sort(lesser_cmp, lesser) ++ h::sort(lesser_cmp, bigger)
/** Puts `delim` between every two members of the list
*/
function intersperse(delim : 'a, l : list('a)) : list('a) = intersperse_(delim, l, []) function intersperse(delim : 'a, l : list('a)) : list('a) = intersperse_(delim, l, [])
private function intersperse_(delim : 'a, l : list('a), acc : list('a)) : list('a) = switch(l) private function intersperse_(delim : 'a, l : list('a), acc : list('a)) : list('a) = switch(l)
[] => reverse(acc) [] => reverse(acc)
@ -207,6 +238,8 @@ namespace List =
h::t => intersperse_(delim, t, delim::h::acc) h::t => intersperse_(delim, t, delim::h::acc)
/** Effectively a zip with an infinite sequence of natural numbers
*/
function enumerate(l : list('a)) : list(int * 'a) = enumerate_(l, 0, []) function enumerate(l : list('a)) : list(int * 'a) = enumerate_(l, 0, [])
private function enumerate_(l : list('a), n : int, acc : list(int * 'a)) : list(int * 'a) = switch(l) private function enumerate_(l : list('a), n : int, acc : list(int * 'a)) : list(int * 'a) = switch(l)
[] => reverse(acc) [] => reverse(acc)

View File

@ -10,13 +10,18 @@ namespace Option =
None => false None => false
Some(_) => true Some(_) => true
/** Catamorphism on `option`. Also known as inlined pattern matching.
*/
function match(n : 'b, s : 'a => 'b, o : option('a)) : 'b = switch(o) function match(n : 'b, s : 'a => 'b, o : option('a)) : 'b = switch(o)
None => n None => n
Some(x) => s(x) Some(x) => s(x)
/** Escape option providing default if `None`
*/
function default(def : 'a, o : option('a)) : 'a = match(def, (x) => x, o) function default(def : 'a, o : option('a)) : 'a = match(def, (x) => x, o)
/** Assume it is `Some`
*/
function force(o : option('a)) : 'a = default(abort("Forced None value"), o) function force(o : option('a)) : 'a = default(abort("Forced None value"), o)
function on_elem(o : option('a), f : 'a => unit) : unit = match((), f, o) function on_elem(o : option('a), f : 'a => unit) : unit = match((), f, o)
@ -40,10 +45,14 @@ namespace Option =
(Some(x1), Some(x2), Some(x3)) => Some(f(x1, x2, x3)) (Some(x1), Some(x2), Some(x3)) => Some(f(x1, x2, x3))
_ => None _ => None
/** Like `map`, but the function is in `option`
*/
function app_over(f : option ('a => 'b), o : option('a)) : option('b) = switch((f, o)) function app_over(f : option ('a => 'b), o : option('a)) : option('b) = switch((f, o))
(Some(ff), Some(xx)) => Some(ff(xx)) (Some(ff), Some(xx)) => Some(ff(xx))
_ => None _ => None
/** Monadic bind
*/
function flat_map(f : 'a => option('b), o : option('a)) : option('b) = switch(o) function flat_map(f : 'a => option('b), o : option('a)) : option('b) = switch(o)
None => None None => None
Some(x) => f(x) Some(x) => f(x)
@ -53,22 +62,31 @@ namespace Option =
None => [] None => []
Some(x) => [x] Some(x) => [x]
/** Turns list of options into a list of elements that are under `Some`s.
* Safe.
*/
function filter_options(l : list(option('a))) : list('a) = filter_options_(l, []) function filter_options(l : list(option('a))) : list('a) = filter_options_(l, [])
private function filter_options_(l : list (option('a)), acc : list('a)) : list('a) = switch(l) private function filter_options_(l : list (option('a)), acc : list('a)) : list('a) = switch(l)
[] => List.reverse(acc) [] => List.reverse(acc)
None::t => filter_options_(t, acc) None::t => filter_options_(t, acc)
Some(x)::t => filter_options_(t, x::acc) Some(x)::t => filter_options_(t, x::acc)
/** Just like `filter_options` but requires all elements to be `Some` and returns
* None if any of them is not
*/
function seq_options(l : list (option('a))) : option (list('a)) = seq_options_(l, []) function seq_options(l : list (option('a))) : option (list('a)) = seq_options_(l, [])
private function seq_options_(l : list (option('a)), acc : list('a)) : option(list('a)) = switch(l) private function seq_options_(l : list (option('a)), acc : list('a)) : option(list('a)) = switch(l)
[] => Some(List.reverse(acc)) [] => Some(List.reverse(acc))
None::t => None None::t => None
Some(x)::t => seq_options_(t, x::acc) Some(x)::t => seq_options_(t, x::acc)
/** Choose `Some` out of two if possible
*/
function choose(o1 : option('a), o2 : option('a)) : option('a) = function choose(o1 : option('a), o2 : option('a)) : option('a) =
if(is_some(o1)) o1 else o2 if(is_some(o1)) o1 else o2
/** Choose `Some` from list of options if possible
*/
function choose_first(l : list(option('a))) : option('a) = switch(l) function choose_first(l : list(option('a))) : option('a) = switch(l)
[] => None [] => None
None::t => choose_first(t) None::t => choose_first(t)

View File

@ -6,12 +6,18 @@ namespace Pair =
function snd(t : ('a * 'b)) : 'b = switch(t) function snd(t : ('a * 'b)) : 'b = switch(t)
(_, y) => y (_, y) => y
/** Map over first
*/
function map1(f : 'a => 'c, t : ('a * 'b)) : ('c * 'b) = switch(t) function map1(f : 'a => 'c, t : ('a * 'b)) : ('c * 'b) = switch(t)
(x, y) => (f(x), y) (x, y) => (f(x), y)
/** Map over second
*/
function map2(f : 'b => 'c, t : ('a * 'b)) : ('a * 'c) = switch(t) function map2(f : 'b => 'c, t : ('a * 'b)) : ('a * 'c) = switch(t)
(x, y) => (x, f(y)) (x, y) => (x, f(y))
/** Map over both
*/
function bimap(f : 'a => 'c, g : 'b => 'd, t : ('a * 'b)) : ('c * 'd) = switch(t) function bimap(f : 'a => 'c, g : 'b => 'd, t : ('a * 'b)) : ('c * 'd) = switch(t)
(x, y) => (f(x), g(y)) (x, y) => (f(x), g(y))

View File

@ -10,15 +10,23 @@ namespace Triple =
(_, _, z) => z (_, _, z) => z
/** Map over first
*/
function map1(f : 'a => 'm, t : ('a * 'b * 'c)) : ('m * 'b * 'c) = switch(t) function map1(f : 'a => 'm, t : ('a * 'b * 'c)) : ('m * 'b * 'c) = switch(t)
(x, y, z) => (f(x), y, z) (x, y, z) => (f(x), y, z)
/** Map over second
*/
function map2(f : 'b => 'm, t : ('a * 'b * 'c)) : ('a * 'm * 'c) = switch(t) function map2(f : 'b => 'm, t : ('a * 'b * 'c)) : ('a * 'm * 'c) = switch(t)
(x, y, z) => (x, f(y), z) (x, y, z) => (x, f(y), z)
/** Map over third
*/
function map3(f : 'c => 'm, t : ('a * 'b * 'c)) : ('a * 'b * 'm) = switch(t) function map3(f : 'c => 'm, t : ('a * 'b * 'c)) : ('a * 'b * 'm) = switch(t)
(x, y, z) => (x, y, f(z)) (x, y, z) => (x, y, f(z))
/** Map over all elements
*/
function trimap( f : 'a => 'x function trimap( f : 'a => 'x
, g : 'b => 'y , g : 'b => 'y
, h : 'c => 'z , h : 'c => 'z
@ -29,9 +37,13 @@ namespace Triple =
function swap(t : ('a * 'b * 'c)) : ('c * 'b * 'a) = switch(t) function swap(t : ('a * 'b * 'c)) : ('c * 'b * 'a) = switch(t)
(x, y, z) => (z, y, x) (x, y, z) => (z, y, x)
/** Right rotation
*/
function rotr(t : ('a * 'b * 'c)) : ('c * 'a * 'b) = switch(t) function rotr(t : ('a * 'b * 'c)) : ('c * 'a * 'b) = switch(t)
(x, y, z) => (z, x, y) (x, y, z) => (z, x, y)
/** Left rotation
*/
function rotl(t : ('a * 'b * 'c)) : ('b * 'c * 'a) = switch(t) function rotl(t : ('a * 'b * 'c)) : ('b * 'c * 'a) = switch(t)
(x, y, z) => (y, z, x) (x, y, z) => (y, z, x)