@beenotung/tslib
Version:
utils library in Typescript
295 lines • 9.1 kB
JavaScript
;
/**
* Created by beenotung on 12/26/16.
* the curried functions are deprecated due to type system limit
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.map2 = exports.update = exports.groupByAll = exports.mergeObjs = exports.pushAll = exports.concatAll = exports.concat = exports.foldl1 = exports.foldl = exports.groupBy = exports.getOrSetDefault = exports.map = exports.fmap = exports.concatWithoutDup = exports.iteratorsToArray = 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;
const curry_1 = require("./curry");
const map_1 = require("./map");
/** take all args (ignore arity)
* apply :: (..args->a) -> ...args -> a
* */
exports.apply = curry_1.curry((f) => function () {
return curry_1.id(f.apply(null, arguments));
});
exports.prop = curry_1.curry((name, o) => o[name]);
/** cannot represent recursive type, o must eventually contains type A */
exports.deepProp = 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 = curry_1.curry((a, k, o) => {
o[k] = a;
return o;
});
exports.length = curry_1.curry((x) => x.length);
exports.filter = curry_1.curry((f, xs) => xs.filter(f));
exports.compose = curry_1.curry((f, g, a) => f(g(a)));
/**
* flip :: (a->b) -> (b->a)
* */
exports.flip = curry_1.curry((f) => (b) => (a) => f(a, b));
/**
* lift :: a -> b -> a
* */
exports.lift = curry_1.curry((a, b) => a);
exports.lift_noarg = curry_1.curry((a) => () => a);
exports.liftError = curry_1.curry((e, b) => {
throw e;
});
exports.liftError_noarg = curry_1.curry((e) => () => {
throw e;
});
exports.compose2 = exports.compose(exports.compose, exports.compose);
exports.odd = curry_1.curry((x) => x % 2 === 1);
exports.even = curry_1.curry((x) => x % 2 === 0);
exports.countWhere = curry_1.curry(exports.compose2(exports.length, exports.filter));
/**
* @remark side effect
* apply2 :: (a->*) -> (a->b) -> a -> b
* */
exports.apply2 = 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 = exports.flip(exports.apply2)(curry_1.id);
exports.symbolFs = new Map();
exports.isFunctionType = (x) => typeof x === 'function';
exports.isNumberType = (x) => typeof x === 'number';
exports.isStringType = (x) => typeof x === 'string';
/**
* @remark side effect
*
* forEach :: (a->*) -> [a] -> *
* */
exports.forEach = 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 = curry_1.curry((x) => [x]);
/**
* none :: * -> []
* */
exports.none = curry_1.curry((x) => []);
exports.eq = curry_1.curry((a, b) => b === a);
exports.neq = curry_1.curry((a, b) => b !== a);
exports.gt = curry_1.curry((a, b) => b > a);
exports.lt = curry_1.curry((a, b) => b < a);
/**
* first :: (a->Bool) -> [a] -> MaybeSingleton a
* */
exports.first = curry_1.curry((f, xs) => {
for (const x of xs) {
if (f(x)) {
return exports.just(x);
}
}
return exports.none();
});
/**
* any :: (a->Bool) -> [a] -> Bool
* */
exports.any = 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 = curry_1.curry((name, f) => {
exports.symbolFs.set(name, f);
return f;
});
/* number | string atomically for a and b */
exports.add = exports.defineSymbolF('+', (a, b) => b + a);
/* number | string atomically for a and b */
exports.minus = exports.defineSymbolF('-', (a, b) => b - a);
exports.mult = exports.defineSymbolF('*', (a, b) => b * a);
exports.defineSymbolF('/', (a, b) => b / a);
exports.rem = exports.defineSymbolF('%', (a, b) => b % a);
exports.div = curry_1.curry((a, b) => Math.floor(b / a));
/* tslint:disable no-bitwise */
exports.quot = curry_1.curry((a, b) => (b / a) | 0);
/** faster */
exports.quotMod = curry_1.curry((a, b) => [
(b / a) | 0,
b % a,
]);
/* tslint:enable no-bitwise */
/* slower */
exports.divMod = curry_1.curry((a, b) => {
const d = Math.floor(b / a);
return [d, b - d * a];
});
exports.and = exports.defineSymbolF('&&', (a, b) => b && a);
exports.or = exports.defineSymbolF('||', (a, b) => b || a);
exports.not = exports.defineSymbolF('!', (a) => !a);
exports.notnot = exports.defineSymbolF('!!', (a) => !!a);
exports.symbolF = curry_1.curry((name) => exports.symbolFs.get(name) ||
(() => {
throw new Error('symbol ' + name + ' is not defined');
})());
exports.composeFs = curry_1.curry((fs, acc) => {
for (let i = fs.length - 1; i >= 0; i--) {
acc = fs[i](acc);
}
return acc;
});
exports.chainFs = 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 = 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.iteratorsToArray = iteratorsToArray;
exports.concatWithoutDup = curry_1.curry((as, bs) => {
const acc = new Set();
exports.doAll((as) => exports.doAll((a) => acc.add(a), as), [as, bs]);
return iteratorsToArray([acc.values()]);
});
exports.fmap = curry_1.curry((f, as) => as.map(f));
/**@deprecated*/
exports.map = exports.fmap;
/**@deprecated use mapGetOrSetDefault in map.ts */
exports.getOrSetDefault = curry_1.curry((v, k, m) => {
if (m.has(k)) {
return m.get(k);
}
m.set(k, v);
return v;
});
/**
* groupBy :: (a->k) , [a] -> Map k [a]
* */
function groupBy(f, xs) {
const res = new Map();
for (const x of xs) {
map_1.mapGetOrSetDefault(res, f(x), () => []).push(x);
}
return res;
}
exports.groupBy = groupBy;
/**
* foldl :: (b->a->b) -> b -> [a] -> b
* */
exports.foldl = 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 = 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 = curry_1.curry((as, bs) => as.concat(bs));
/**
* concatAll :: [[a]] -> [a]
* */
exports.concatAll = exports.foldl(exports.concat, []);
/**
* @remark side effect to as
* as -> bs -> __update as__
* */
exports.pushAll = 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 = curry_1.curry((xs) => Object.assign({}, ...xs));
// /**
// * mergeAll :: (a=>) -> [a] -> [a] -> [a]
// * */
// export const mergeAll = curry((f, as, bs) => {
// as = groupBy(f, as);
// bs = groupBy(f, bs);
// const res = [];
// forEach(xs => pushAll(res), as);
// forEach(xs => pushAll(res), bs);
// return res;
// });
/**
* groupByAll :: (a->k) -> [[a]] -> Map k [a]
* */
exports.groupByAll = curry_1.curry((f, xss) => {
const res = new Map();
for (const xs of xss) {
for (const x of xs) {
exports.getOrSetDefault([], f(x), res).push(x);
}
}
return res;
});
/**
* @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 = curry_1.curry((f, as) => {
as.forEach(f);
return as;
});
exports.map2 = curry_1.curry((f, xss) => {
return xss.map(xs => xs.map(f));
});
//# sourceMappingURL=functional.js.map