star/lib/rt.js

235 lines
3.9 KiB
JavaScript

"use strict";
function variant(tag, value) {
return value === undefined ? { tag } : { tag, value };
}
function match(value, cases) {
if (!value || typeof value.tag !== 'string') {
throw new Error('match: expected variant value');
}
const handler = cases[value.tag] || cases._;
if (!handler) {
throw new Error(`match: unhandled variant tag: ${value.tag}`);
}
return handler(value.value);
}
const nil = [];
function cons(head, tail) {
return [head, ...tail];
}
function head(list) {
if (list.length === 0) {
throw new Error('head: empty list');
}
return list[0];
}
function tail(list) {
if (list.length === 0) {
throw new Error('tail: empty list');
}
return list.slice(1);
}
function isEmpty(list) {
return list.length === 0;
}
function length(list) {
return list.length;
}
function map(f, list) {
return list.map(f);
}
function filter(pred, list) {
return list.filter(pred);
}
function foldl(f, acc, list) {
return list.reduce(f, acc);
}
function foldr(f, acc, list) {
return list.reduceRight((acc, x) => f(x, acc), acc);
}
function concat(list1, list2) {
return [...list1, ...list2];
}
function reverse(list) {
return list.slice().reverse();
}
function take(n, list) {
return list.slice(0, n);
}
function drop(n, list) {
return list.slice(n);
}
const None = variant('None');
function Some(value) {
return variant('Some', value);
}
function isSome(opt) {
return opt.tag === 'Some';
}
function isNone(opt) {
return opt.tag === 'None';
}
function unwrap(opt) {
if (opt.tag === 'None') {
throw new Error('unwrap: None value');
}
return opt.value;
}
function unwrapOr(opt, defaultValue) {
return opt.tag === 'Some' ? opt.value : defaultValue;
}
function Ok(value) {
return variant('Ok', value);
}
function Err(error) {
return variant('Err', error);
}
function isOk(result) {
return result.tag === 'Ok';
}
function isErr(result) {
return result.tag === 'Err';
}
function toString(value) {
if (value === null || value === undefined) {
return 'null';
}
if (Array.isArray(value)) {
return '[' + value.map(toString).join(', ') + ']';
}
if (typeof value === 'object' && value.tag) {
return value.value === undefined
? value.tag
: `${value.tag}(${toString(value.value)})`;
}
return String(value);
}
function strLength(str) {
return str.length;
}
function strConcat(str1, str2) {
return str1 + str2;
}
function substring(str, start, length) {
return str.substr(start, length);
}
function intDiv(a, b) {
return Math.floor(a / b);
}
function pow(base, exp) {
return Math.pow(base, exp);
}
function abs(x) {
return Math.abs(x);
}
function print(value) {
console.log(toString(value));
}
function printStr(value) {
process.stdout.write(toString(value));
}
function id(x) {
return x;
}
function constant(x) {
return () => x;
}
function compose(f, g) {
return x => f(g(x));
}
function pipe(value, f) {
return f(value);
}
function curry(f, arity = f.length) {
return function curried(...args) {
if (args.length >= arity) {
return f(...args);
}
return (...moreArgs) => curried(...args, ...moreArgs);
};
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
variant,
match,
nil,
cons,
head,
tail,
isEmpty,
length,
map,
filter,
foldl,
foldr,
concat,
reverse,
take,
drop,
None,
Some,
isSome,
isNone,
unwrap,
unwrapOr,
Ok,
Err,
isOk,
isErr,
toString,
strLength,
strConcat,
substring,
intDiv,
pow,
abs,
print,
printStr,
id,
constant,
compose,
pipe,
curry
};
}