UNPKG

@beenotung/tslib

Version:
291 lines (290 loc) 9.18 kB
"use strict"; /** * Created by beenotung on 12/26/16. * the curried functions are deprecated due to type system limit */ Object.defineProperty(exports, "__esModule", { value: true }); exports.fmap = exports.concatWithoutDup = exports.doAll = exports.chainFs = exports.composeFs = exports.symbolF = exports.notnot = exports.not = exports.or = exports.and = exports.divMod = exports.quotMod = exports.quot = exports.div = exports.rem = exports.mult = exports.minus = exports.add = exports.defineSymbolF = exports.any = exports.first = exports.lt = exports.gt = exports.neq = exports.eq = exports.none = exports.just = exports.forEach = exports.isStringType = exports.isNumberType = exports.isFunctionType = exports.symbolFs = exports.echoF = exports.apply2 = exports.countWhere = exports.even = exports.odd = exports.compose2 = exports.liftError_noarg = exports.liftError = exports.lift_noarg = exports.lift = exports.flip = exports.compose = exports.filter = exports.length = exports.setProp = exports.deepProp = exports.prop = exports.apply = void 0; exports.map2 = exports.update = exports.groupByAll = exports.mergeAll = exports.mergeObjs = exports.pushAll = exports.concatAll = exports.concat = exports.foldl1 = exports.foldl = void 0; exports.iteratorsToArray = iteratorsToArray; exports.groupBy = groupBy; const curry_1 = require("./curry"); const map_1 = require("./map"); /** take all args (ignore arity) * apply :: (..args->a) -> ...args -> a * */ exports.apply = (0, curry_1.curry)((f) => function () { return (0, curry_1.id)(f.apply(null, arguments)); }); exports.prop = (0, curry_1.curry)((name, o) => o[name]); /** cannot represent recursive type, o must eventually contains type A */ exports.deepProp = (0, curry_1.curry)((name, o) => { if (o[name] !== void 0) { return o[name]; } else { return name.split('.').reduce((acc, c) => acc[c], o); } }); /** * @remark side effect * @return original object * * setProp :: a -> k -> {k:a} -> {k:a} * */ exports.setProp = (0, curry_1.curry)((a, k, o) => { o[k] = a; return o; }); exports.length = (0, curry_1.curry)((x) => x.length); exports.filter = (0, curry_1.curry)((f, xs) => xs.filter(f)); exports.compose = (0, curry_1.curry)((f, g, a) => f(g(a))); /** * flip :: (a->b) -> (b->a) * */ exports.flip = (0, curry_1.curry)((f) => (b) => (a) => f(a, b)); /** * lift :: a -> b -> a * */ exports.lift = (0, curry_1.curry)((a, _b) => a); exports.lift_noarg = (0, curry_1.curry)((a) => () => a); exports.liftError = (0, curry_1.curry)((e, _b) => { throw e; }); exports.liftError_noarg = (0, curry_1.curry)((e) => () => { throw e; }); exports.compose2 = (0, exports.compose)(exports.compose, exports.compose); exports.odd = (0, curry_1.curry)((x) => x % 2 === 1); exports.even = (0, curry_1.curry)((x) => x % 2 === 0); exports.countWhere = (0, curry_1.curry)((0, exports.compose2)(exports.length, exports.filter)); /** * @remark side effect * apply2 :: (a->*) -> (a->b) -> a -> b * */ exports.apply2 = (0, curry_1.curry)((f, g, x) => { f(x); return g(x); }); /** * echoF :: (a->*) -> a -> a * @example echoF (console.log) (1) ~> console.log(1) +> return 1 * */ exports.echoF = (0, exports.flip)(exports.apply2)(curry_1.id); exports.symbolFs = new Map(); const isFunctionType = (x) => typeof x === 'function'; exports.isFunctionType = isFunctionType; const isNumberType = (x) => typeof x === 'number'; exports.isNumberType = isNumberType; const isStringType = (x) => typeof x === 'string'; exports.isStringType = isStringType; /** * @remark side effect * * forEach :: (a->*) -> [a] -> * * */ exports.forEach = (0, curry_1.curry)((f, xs) => { /* xs is ArrayLike, might not has forEach */ const n = xs.length; for (let i = 0; i < n; i++) { f(xs[i]); } }); /** * just :: a -> [a] * */ exports.just = (0, curry_1.curry)((x) => [x]); /** * none :: * -> [] * */ exports.none = (0, curry_1.curry)((_x) => []); exports.eq = (0, curry_1.curry)((a, b) => b === a); exports.neq = (0, curry_1.curry)((a, b) => b !== a); exports.gt = (0, curry_1.curry)((a, b) => b > a); exports.lt = (0, curry_1.curry)((a, b) => b < a); /** * first :: (a->Bool) -> [a] -> MaybeSingleton a * */ exports.first = (0, curry_1.curry)((f, xs) => { for (const x of xs) { if (f(x)) { return (0, exports.just)(x); } } return (0, exports.none)(); }); /** * any :: (a->Bool) -> [a] -> Bool * */ exports.any = (0, curry_1.curry)((f, xs) => { for (const x of xs) { if (f(x)) { return true; } } return false; }); /** * @remark side effect * define infix operator (binary function) * */ exports.defineSymbolF = (0, curry_1.curry)((name, f) => { exports.symbolFs.set(name, f); return f; }); /* number | string atomically for a and b */ exports.add = (0, exports.defineSymbolF)('+', (a, b) => b + a); /* number | string atomically for a and b */ exports.minus = (0, exports.defineSymbolF)('-', (a, b) => b - a); exports.mult = (0, exports.defineSymbolF)('*', (a, b) => b * a); (0, exports.defineSymbolF)('/', (a, b) => b / a); exports.rem = (0, exports.defineSymbolF)('%', (a, b) => b % a); exports.div = (0, curry_1.curry)((a, b) => Math.floor(b / a)); exports.quot = (0, curry_1.curry)((a, b) => (b / a) | 0); /** faster */ exports.quotMod = (0, curry_1.curry)((a, b) => [ (b / a) | 0, b % a, ]); /* slower */ exports.divMod = (0, curry_1.curry)((a, b) => { const d = Math.floor(b / a); return [d, b - d * a]; }); exports.and = (0, exports.defineSymbolF)('&&', (a, b) => b && a); exports.or = (0, exports.defineSymbolF)('||', (a, b) => b || a); exports.not = (0, exports.defineSymbolF)('!', (a) => !a); exports.notnot = (0, exports.defineSymbolF)('!!', (a) => !!a); exports.symbolF = (0, curry_1.curry)((name) => exports.symbolFs.get(name) || (() => { throw new Error('symbol ' + name + ' is not defined'); })()); exports.composeFs = (0, curry_1.curry)((fs, acc) => { for (let i = fs.length - 1; i >= 0; i--) { acc = fs[i](acc); } return acc; }); exports.chainFs = (0, curry_1.curry)((fs, acc) => { for (const f of fs) { acc = f(acc); } return acc; }); /** * @remark side effect * f :: unary function <A,B> * args :: ArrayLike<A> * */ exports.doAll = (0, curry_1.curry)((f, args) => { for (const arg of args) { f(arg); } }); /** * flatten the iterators as a single array * */ function iteratorsToArray(itrs) { const xs = []; for (const itr of itrs) { xs.push(...Array.from(itr)); } return xs; } exports.concatWithoutDup = (0, curry_1.curry)((as, bs) => { const acc = new Set(); (0, exports.doAll)((as) => (0, exports.doAll)((a) => acc.add(a), as), [as, bs]); return iteratorsToArray([acc.values()]); }); exports.fmap = (0, curry_1.curry)((f, as) => as.map(f)); /** * groupBy :: (a->k) , [a] -> Map k [a] * */ function groupBy(f, xs) { const res = new Map(); for (const x of xs) { (0, map_1.mapGetOrSetDefault)(res, f(x), () => []).push(x); } return res; } /** * foldl :: (b->a->b) -> b -> [a] -> b * */ exports.foldl = (0, curry_1.curry)((f, acc, xs) => { for (let i = 0, n = xs.length; i < n; i++) { acc = f(acc, xs[i]); } return acc; }); exports.foldl1 = (0, curry_1.curry)((f, xs) => { const n = xs.length; if (n === 0) { throw new TypeError('xs should be non-empty ArrayLike<*>'); } let acc = xs[0]; for (let i = 1; i < n; i++) { acc = f(acc, xs[i]); } return acc; }); /** * concat :: [a] -> [a] -> [a] * */ exports.concat = (0, curry_1.curry)((as, bs) => as.concat(bs)); /** * concatAll :: [[a]] -> [a] * */ exports.concatAll = (0, exports.foldl)(exports.concat, []); /** * @remark side effect to as * as -> bs -> __update as__ * */ exports.pushAll = (0, curry_1.curry)((as, bs) => as.push(...bs)); /** * merge array of plain objects * do not support merging functions * do not support instant object (e.g. Map instance) * merge :: [a|b] -> a & b * */ exports.mergeObjs = (0, curry_1.curry)((xs) => Object.assign({}, ...xs)); /** * mergeAll :: (a=>) -> [a] -> [a] -> [a] * */ exports.mergeAll = (0, curry_1.curry)((f, as, bs) => { const map = new Map(); for (const xs of [as, bs]) { for (const x of xs) { map.set(f(x), x); } } return Array.from(map.values()); }); /** * groupByAll :: (a->k) -> [[a]] -> Map k [a] * */ exports.groupByAll = (0, curry_1.curry)((f, xss) => { const res = new Map(); for (const xs of xss) { for (const x of xs) { (0, map_1.mapGetOrSetDefault)(res, f(x), newArray).push(x); } } return res; }); function newArray() { return []; } /** * @remark side effect * update :: (a->__update a__) -> [a] -> [a] * @return original array * * more effective then using map if the original array is going to be discarded anyway * */ exports.update = (0, curry_1.curry)((f, as) => { as.forEach(f); return as; }); exports.map2 = (0, curry_1.curry)((f, xss) => { return xss.map(xs => xs.map(f)); });