I propose here a suite of functions that I found myself reaching for, and missing in the standard library. I present them in ucode, as that's how I use them; possibly, they should be implemented in C instead.
The tests at the end demonstrates what the functions do.
General-purpose functions, most of them for analyzing or manipulating arrays. A source of inspiration is Python's itertools. However, as ucode does not have iterators with lazy evaluation (right?), some of the itertools functions do not make sense in ucode, and some other might be less efficient.
The pretty printer was written before I learned that there already is one! However, I think I can offer two improvements with my version: it prints [ ] and { } on a single line, and it breaks arrays and objects into multiple lines only when needed to avoid values being too long. Also I'm happy about how short the function could be made (after several rewrites).
Returns random data in a few useful forms. Gets its randomness from /dev/random.
#!/usr/bin/env ucode
import {uniform, foldl, foldr, bool, all, any, equal, concat, cartesian, takewhile, dropwhile, compose, id, transpose, zip, map_n, map_arr, sum, product, range, repeat, enumerate} from "./lib/general.uc";
import {println, pretty, prettyprint, prettyprintln} from "./lib/printing.uc";
import {rand_bytes, rand_int, rand_hex, rand_dec, rand_choose} from "./lib/random.uc";
import {iso8601} from "./lib/time.uc";
// id
assert(id(5) == 5);
assert(id("abc") == "abc");
assert(id(null) == null);
assert(id(id) == id);
assert(equal(id([0, 1, 2]), [0, 1, 2]));
assert(equal(id({a: 5, b: 6}), {a: 5, b: 6}));
// uniform
assert( uniform([5, 5, 5, 5]));
assert(!uniform([5, 5, 4, 5]));
assert(uniform([]));
// foldl
assert(foldl((a, b) => a + b, 0, [4, 5, 6, 7, 8]) == ((((0 + 4) + 5) + 6) + 7) + 8);
assert(foldl((a, b) => a * b, 1, [4, 5, 6, 7, 8]) == ((((1 * 4) * 5) * 6) * 7) * 8);
assert(foldl((a, b) => a ? "(" + a + "," + b + ")" : b, "", [4, 5, 6, 7, 8]) == "((((4,5),6),7),8)");
// foldr
assert(foldr((a, b) => a + b, 0, [4, 5, 6, 7, 8]) == 4 + (5 + (6 + (7 + 8))));
assert(foldr((a, b) => a * b, 1, [4, 5, 6, 7, 8]) == 4 * (5 * (6 * (7 * 8))));
assert(foldr((a, b) => b ? "(" + a + "," + b + ")" : a, "", [4, 5, 6, 7, 8]) == "(4,(5,(6,(7,8))))");
// bool
assert(bool(5) == true);
assert(bool(0) == false);
assert(bool("") == false);
assert(bool([]) == true);
assert(bool(null) == false);
// all
assert( all([true, true, true, true]));
assert(!all([true, true, false, true]));
assert( all([4, 5, 6, 7]));
assert(!all([4, 5, 0, 7]));
assert(all([]));
// any
assert(!any([false, false, false, false]));
assert( any([0, 0, 6, 0]));
assert(!any([0, 0, 0, 0]));
assert(!any([]));
assert(!any([0, 0.0, NaN, false, "", null]));
// concat
assert(equal(concat([0, 1, 2], ["a", "b", "c"], [0.0, 1.0, 2.0]), [0, 1, 2, "a", "b", "c", 0.0, 1.0, 2.0]));
assert(equal(concat([]), []));
assert(equal(concat(), []));
// cartesian
assert(equal(cartesian(["a", "b", "c"], [0, 1, 2]), [["a", 0], ["a", 1], ["a", 2], ["b", 0], ["b", 1], ["b", 2], ["c", 0], ["c", 1], ["c", 2]]));
assert(equal(cartesian([1,2], [10,20], [100,200]), [[1,10,100],[1,10,200],[1,20,100],[1,20,200],[2,10,100],[2,10,200],[2,20,100],[2,20,200]]));
assert(equal(cartesian([1,2,3], []), []));
assert(equal(cartesian([], [1,2,3]), []));
assert(equal(cartesian(), [[]]));
// takewhile
assert(equal(takewhile(x => (x < 6), [3, 4, 5, 6, 7, 8, 0, 1, 2]), [3, 4, 5 ]));
assert(equal(takewhile(x => (x > 6), [3, 4, 5, 6, 7, 8, 0, 1, 2]), [ ]));
assert(equal(takewhile(x => (x >= 0), [3, 4, 5, 6, 7, 8, 0, 1, 2]), [3, 4, 5, 6, 7, 8, 0, 1, 2]));
assert(equal(takewhile(x => (x < 0), [3, 4, 5, 6, 7, 8, 0, 1, 2]), [ ]));
// dropwhile
assert(equal(dropwhile(x => (x < 6), [3, 4, 5, 6, 7, 8, 0, 1, 2]), [ 6, 7, 8, 0, 1, 2]));
assert(equal(dropwhile(x => (x > 6), [3, 4, 5, 6, 7, 8, 0, 1, 2]), [3, 4, 5, 6, 7, 8, 0, 1, 2]));
assert(equal(dropwhile(x => (x >= 0), [3, 4, 5, 6, 7, 8, 0, 1, 2]), [ ]));
assert(equal(dropwhile(x => (x < 0), [3, 4, 5, 6, 7, 8, 0, 1, 2]), [3, 4, 5, 6, 7, 8, 0, 1, 2]));
// compose
{
let f = compose(b64enc, b64dec, hexenc, hexdec);
assert(f("abcdefghijklm") == "abcdefghijklm");
}
{
let g = compose(x => map(x, type), sort, uniq, uc);
assert(
g([3, 3.0, "", "asdf", id, [0, 1, 2], {}, {a: 5}]) ==
'[ "ARRAY", "DOUBLE", "FUNCTION", "INT", "OBJECT", "STRING" ]'
);
}
// transpose
assert(equal(transpose([[1, 2, 3], [11, 22, 33]]), [[1, 11], [2, 22], [3, 33 ]]));
// zip
assert(equal(zip([1, 2], [11, 22], [111, 222]), [[1, 11, 111], [2, 22, 222]]));
// map_n
assert(equal(map_n(index, ["cow", "milk", "butter"], ["w", "i", "a"]), [2, 1, -1]));
// map_arr
assert(equal(map_arr(index, [["cow", "milk", "butter"], ["w", "i", "a"]]), [2, 1, -1]));
// equal
assert( equal([4, 5, 6, 7, 8], [4, 5, 6, 7, 8]));
assert(!equal([4, 5, 6, 7, 8], [4, 5, 6, 1, 8]));
assert(!equal([4, 5, 6, 7, 8], [4, 5, 6, 7 ]));
assert(!equal(0, null));
assert(!equal(0, ""));
assert(!equal(0, "0"));
assert(!equal(0, false));
assert(!equal(1, true));
assert(!equal(null, ""));
assert(!equal(null, "0"));
assert(!equal("0", ""));
assert(equal([], []));
assert(equal([[]], [[]]));
assert(equal([[], 5], [[], 5]));
assert( equal({a: 5, b: "asdf"}, {a: 5, b: "asdf" }));
assert( equal({a: 5, b: "asdf"}, {b: "asdf", a: 5 }));
assert(!equal({a: 5, b: "asdf"}, {b: "asdf", a: 6 }));
{
let x = {
a: true,
b: false,
c: 0,
d: 1,
e: 0.0,
f: 1.0,
g: "asdf",
h: "",
i: [],
j: [1, 2, 3],
k: [0, [], [[3, false], "aaa"]],
l: {foo: true, "bar": 123},
m: null,
n: id,
};
let y = {
a: true,
b: false,
c: 0,
d: 1,
e: 0.0,
f: 1.0,
g: "asdf",
h: "",
i: [],
j: [1, 2, 3],
k: [0, [], [[3, false], "aaa"]],
l: {foo: true, "bar": 123},
m: null,
n: id,
};
assert(equal(x, y));
}
// sum
assert(sum([0, 0, 0, 0, 0]) == 0);
assert(sum([4, 5, 6, 7, 8]) == 4 + 5 + 6 + 7 + 8);
assert(sum([]) == 0);
// product
assert(product([1, 1, 1, 1, 1]) == 1);
assert(product([4, 5, 6, 7, 8]) == 4 * 5 * 6 * 7 * 8);
assert(product([]) == 1);
assert(product([1, 2, 3, 0, 4, 5, 6]) == 0);
// range
assert(equal(range(3, 9), [3, 4, 5, 6, 7, 8]));
// repeat
assert(equal(repeat(7, 3), [7, 7, 7]));
assert(equal(repeat(7, 0), []));
// enumerate
assert(equal(enumerate(["x", "y", "z"]), [[0, "x"], [1, "y"], [2, "z"]]));
// iso8601
assert(iso8601([0, 0]) == "1970-01-01T00:00:00,000000000Z");
assert(iso8601([0, 1]) == "1970-01-01T00:00:00,000000001Z");
assert(iso8601([1, 0]) == "1970-01-01T00:00:01,000000000Z");
// println
// Prints to stdout. Not tested.
// pretty
for (let e in [true, false, -5, 0, 5, -5.2, 0.0, 5.2, id, enumerate]) {
assert(pretty(e) == sprintf("%J", e), e);
}
{
let obj = {a: 5, b: [], c: [[4,5,6,7,8,99], {x: "asdf", y: null}], d: {a: true, b: false, c: 0, d: {}, e: 0.0, f: 1.0, g: "a\nsdf", h: "", "i:i": [], asdf: print, j: [1, 2, 3], k: [0, [], [[3, false], "aaa"]], liten: {foo: true, "bar": 123}, m: null, n: id}};
let pretty_string = '{
"a": 5,
"b": [ ],
"c": [
[ 4, 5, 6, 7, 8, 99 ],
{ "x": "asdf", "y": null }
],
"d": {
"a": true,
"b": false,
"c": 0,
"d": { },
"e": 0.0,
"f": 1.0,
"g": "a\\nsdf",
"h": "",
"i:i": [ ],
"asdf": "function print(...) { [native code] }",
"j": [ 1, 2, 3 ],
"k": [
0,
[ ],
[ [ 3, false ], "aaa" ]
],
"liten": { "foo": true, "bar": 123 },
"m": null,
"n": "(x) => { ... }"
}
}';
assert(pretty(obj) == pretty_string);
}
// prettyprint
// Prints to stdout. Not tested.
// prettyprintln
// Prints to stdout. Not tested.
// rand_bytes
// Non-deterministic. Not tested.
// rand_int
// Non-deterministic. Not tested.
// rand_hex
// Non-deterministic. Not tested.
// rand_dec
// Non-deterministic. Not tested.
// rand_choose
// Non-deterministic. Not tested.
I propose here a suite of functions that I found myself reaching for, and missing in the standard library. I present them in ucode, as that's how I use them; possibly, they should be implemented in C instead.
The tests at the end demonstrates what the functions do.
General
General-purpose functions, most of them for analyzing or manipulating arrays. A source of inspiration is Python's itertools. However, as ucode does not have iterators with lazy evaluation (right?), some of the itertools functions do not make sense in ucode, and some other might be less efficient.
Printing
The pretty printer was written before I learned that there already is one! However, I think I can offer two improvements with my version: it prints
[ ]and{ }on a single line, and it breaks arrays and objects into multiple lines only when needed to avoid values being too long. Also I'm happy about how short the function could be made (after several rewrites).Time
Random
Returns random data in a few useful forms. Gets its randomness from
/dev/random.Tests