@hgargg-0710/one
Version:
A tiny npm library purposed for providing beautiful solutions to frequent miniature (one-line/one-expression) tasks for various JS datatypes.
122 lines (121 loc) • 4.43 kB
JavaScript
import { last, lastOut, substitute } from "../array/array.js";
import { not, T } from "../boolean/boolean.js";
import { max } from "../number/number.js";
import { isUndefined } from "../type/type.js";
/**
* Provided with a list of functions, lazily executes them in sequence
* and returns the first truthy result.
* If all results are falsy - returns the last one
*/
export const or = (...fs) => (...x) => fs.reduce((prev, curr) => (prev ? prev : curr(...x)), false);
/**
* Provided with a list of functions, lazily executes them in sequence
* and returns the first falsy result.
* If all results are truthy - returns the last one
*/
export const and = (...fs) => (...x) => fs.reduce((prev, curr) => (prev ? curr(...x) : prev), true);
/**
* Returns the function composition of the `fs` functions.
*/
export const trivialCompose = (...fs) => (...x) => lastOut(fs).reduceRight((last, curr) => curr(last), (last(fs) || id)(...x));
/**
* Returns the array, containing the values of `f(j * i)` for `0 <= i <= floor(n / j)`
*/
export const iterations = (f, n, j = 1) => Array.from({ length: Math.floor(n / j) + +(j > 1) }, (_x, i) => f(j * i));
/**
* Creates a new array `X` = [init],
* that is then filled with `n` iterations of `f(last(X), i, X)`,
* and returned
*/
export const sequence = (f, n) => (init) => {
const seqres = [init];
for (let i = 0; i < n; ++i)
seqres.push(f(last(seqres), i, seqres));
return seqres;
};
/**
* Makes the calls `f(0), f(1), ..., f(n)`
*/
export const repeat = (f, n) => {
for (let i = 0; i < n; ++i)
f(i);
};
/**
* Returns a composition, such that expected output of the given functions are arrays
* intended to be spread out as inputs for the next function.
*/
export const arrayCompose = (...fs) => (...x) => fs.reduceRight((last, curr) => curr(...last), x);
/**
* Creates and returns a `Map`, filled with key-value pairs of `[x, f(x)]` with `x` being in `keys`
*/
export const cache = (f, keys) => new Map(keys.map((x) => [x, f(x)]));
/**
* Breaks the given inputs' array `x` into (possibly intersecting) segments using `x.slice(inds[i])`,
* then - calls the respective function with each segment, and returns all of the calls'
* return values in an array.
*
* A missing `x.slice`-interval defaults to `[]` (whole signature copying)
*/
export const tupleSlice = (...fs) => (...inds) => (...x) => fs.map((f, i) => f(...x.slice(...(inds[i] || []))));
/**
* Similar to `tupleSlice`, only difference being that `inds` are now predicates,
* using which the signatures for each particular function are `x.filter(inds[i])`-ed
*
* Like with `tupleSlice`, the default is copying of the entire signature `.filter(T)`
*/
export const tuplePick = (...fs) => (...inds) => (...x) => fs.map((f, i) => f(...x.filter(inds[i] || T)));
/**
* Returns a function, the inputs of which are cached on each call.
*/
export const cached = (base) => {
const cachef = function (x) {
const cacheval = cachef.cache.get(x);
if (!isUndefined(cacheval))
return cacheval;
const retres = base(x);
cachef.cache.set(x, retres);
return retres;
};
cachef.cache = new Map();
return cachef;
};
/**
* Identity function
*/
export const id = (x) => x;
/**
* No-op function
*/
export const nil = () => { };
/**
* Creates a new function calling `f`, with arguments at positions defined by `indexes` Set
* filled with values from `values`, and the remaining arguments filled with values from 'x'.
*/
export const argFiller = (f) => {
return (...indexes) => {
const substitutionForm = substitute(f.length, indexes);
return (...values) => {
const substituter = substitutionForm(values);
return (...x) => f(...substituter(x));
};
};
};
/**
* Returns `f.bind(bound)`. `bound` defaults to `null`
*/
export const copy = (f, bound = null) => f.bind(bound);
/**
* Returns a function returning `set.has(x)`
*/
export const has = (set) => (x) => set.has(x);
/**
* Returns a function that removes last `n` arguments
* (or, all of them, if it is greater than `args.length`) from `args`,
* and calls `f` on the result
*/
export const argWaster = (f) => (n = Infinity) => (...args) => f(...args.slice(0, max(0, args.length - n)));
/**
* Returns `(...x) => !f(...x)`
*/
export const negate = (f) => trivialCompose(not, f);
export * from "./constant.js";