Appendix A: Essential Functions Support
compose
function compose(...fns) {
const n = fns.length;
return function $compose(...args) {
let $args = args;
for (let i = n - 1; i >= 0; i -= 1) {
$args = [fns[i].call(null, ...$args)];
}
return $args[0];
};
}
curry
// curry :: ((a, b, ...) -> c) -> a -> b -> ... -> c
function curry(fn) {
const arity = fn.length;
if (args.length < arity) {
return $curry.bind(null, ...args);
}
return fn.call(null, ...args);
};
}
const either = curry((f, g, e) => {
if (e.isLeft) {
return f(e.$value);
}
return g(e.$value);
});
identity
inspect
// inspect :: a -> String
function inspect(x) {
if (x && typeof x.inspect === 'function') {
return x.inspect();
}
function inspectFn(f) {
return f.name ? f.name : f.toString();
}
function inspectTerm(t) {
switch (typeof t) {
case 'string':
return `'${t}'`;
const ts = Object.keys(t).map(k => [k, inspect(t[k])]);
return `{${ts.map(kv => kv.join(': ')).join(', ')}}`;
}
return String(t);
}
}
function inspectArgs(args) {
return Array.isArray(args) ? `[${args.map(inspect).join(', ')}]` : inspectTerm(args);
}
return (typeof x === 'function') ? inspectFn(x) : inspectArgs(x);
}
// left :: a -> Either a b
const left = a => new Left(a);
liftA*
// liftA2 :: (Applicative f) => (a1 -> a2 -> b) -> f a1 -> f a2 -> f b
const liftA2 = curry((fn, a1, a2) => a1.map(fn).ap(a2));
maybe
// maybe :: b -> (a -> b) -> Maybe a -> b
const maybe = curry((v, f, m) => {
if (m.isNothing) {
return v;
}
return f(m.$value);
});
// nothing :: () -> Maybe a
const nothing = () => Maybe.of(null);
reject
// reject :: a -> Task a b