fp-ts-std
Version:
The missing pseudo-standard library for fp-ts.
104 lines (103 loc) • 5.44 kB
JavaScript
import { copy } from "fp-ts/Array";
import { reduceM } from "fp-ts/Foldable";
import { concatAll } from "fp-ts/Monoid";
import * as O from "fp-ts/Option";
import { match as orderingMatch } from "fp-ts/Ordering";
import { not } from "fp-ts/Predicate";
import * as RA from "fp-ts/ReadonlyArray";
import * as NEA from "fp-ts/ReadonlyNonEmptyArray";
import * as R from "fp-ts/ReadonlyRecord";
import { max, min } from "fp-ts/Semigroup";
import * as T from "fp-ts/These";
import * as B from "fp-ts/boolean";
import { constant, flip, flow, pipe } from "fp-ts/function";
import { MonoidProduct, MonoidSum, Ord as ordNumber } from "fp-ts/number";
import { invoke } from "./Function";
export const elemV = (eq) => (xs) => y => RA.elem(eq)(y)(xs);
export const none = flow(not, p => RA.every(p));
export const join = (x) => invoke("join")([x]);
export const getDisorderedEq = (ordA) => ({
equals: (xs, ys) => {
const sort = RA.sort(ordA);
return RA.getEq(ordA).equals(sort(xs), sort(ys));
},
});
export const pluckFirst = (p) => (xs) => pipe(RA.findIndex(p)(xs), O.fold(constant([O.none, xs]), i => [
O.some(xs[i]),
RA.unsafeDeleteAt(i, xs),
]));
export const upsert = (eqA) => (x) => (ys) => pipe(RA.findIndex(y => eqA.equals(x, y))(ys), O.map(i => RA.unsafeUpdateAt(i, x, ys)), O.chain(NEA.fromReadonlyArray), O.getOrElse(() => RA.append(x)(ys)));
export const insertMany = (i) => (xs) => (ys) => pipe(xs, RA.reverse, reduceM(O.Monad, RA.Foldable)(ys, (zs, x) => pipe(zs, RA.insertAt(i, x))), O.chain(NEA.fromReadonlyArray));
export const dropRepeats = eq => xs => pipe(xs, RA.filterWithIndex((i, x) => i === 0 || !eq.equals(x, xs[i - 1])));
export const startsWith = (eq) => (start) => flow(RA.takeLeft(start.length), xs => RA.getEq(eq).equals(xs, start));
export const endsWith = (eq) => (end) => flow(RA.takeRight(end.length), xs => RA.getEq(eq).equals(xs, end));
export const without = (eq) => (xs) => flow(RA.filter(y => !RA.elem(eq)(y)(xs)));
export const cartesian = (xs) => (ys) => pipe(xs, RA.chain(x => pipe(ys, RA.map(y => [x, y]))));
export const sum = concatAll(MonoidSum);
export const product = concatAll(MonoidProduct);
export const mean = (xs) => sum(xs) / xs.length;
export const median = flow(NEA.sort(ordNumber), xs => {
const i = xs.length / 2;
return i % 1 === 0 ? (xs[i - 1] + xs[i]) / 2 : xs[Math.floor(i)];
});
export const aperture = (n) => (xs) => {
const go = (i) => (ys) => i + n > xs.length ? ys : go(i + 1)(RA.append(slice(i)(n + i)(xs))(ys));
return n < 1 ? [] : go(0)([]);
};
export const slice = (start) => (end) => invoke("slice")([start, end]);
export const reject = (f) => RA.filter(not(f));
export const moveFrom = (from) => (to) => (xs) => from >= xs.length || to >= xs.length
? O.none
: from === to
? O.some(xs)
: pipe(xs, RA.lookup(from), O.chain(x => pipe(RA.deleteAt(from)(xs), O.chain(RA.insertAt(to, x)))));
export const moveTo = flip(moveFrom);
export const countBy = (f) => (xs) => R.fromFoldableMap(MonoidSum, RA.Foldable)(xs, x => [f(x), 1]);
export const dropRightWhile = (f) => flow(RA.reverse, RA.dropLeftWhile(f), RA.reverse);
export const dropAt = (i) => (n) => (xs) => pipe(RA.isOutOfBound(i, xs), B.fold(() => pipe(copy(Array.from(xs)), ys => {
ys.splice(i, n);
return ys;
}, O.some), constant(O.none)));
export const transpose = (xs) => {
if (RA.isEmpty(xs))
return [];
if (RA.isEmpty(xs[0]))
return transpose(RA.dropLeft(1)(xs));
const [[y, ...ys], ...yss] = xs;
const zs = [y, ...RA.filterMap(RA.head)(yss)];
const zss = [ys, ...RA.map(RA.dropLeft(1))(yss)];
return [zs, ...transpose(zss)];
};
export const takeRightWhile = (f) => flow(RA.reverse, RA.takeLeftWhile(f), RA.reverse);
export const symmetricDifference = (eq) => (xs) => ys => RA.getMonoid().concat(RA.difference(eq)(ys)(xs), RA.difference(eq)(xs)(ys));
export const reduceWhile = (p) => (f) => {
const go = (acc) => (ys) => pipe(NEA.fromReadonlyArray(ys), O.filter(flow(NEA.head, p)), O.fold(constant(acc), flow(NEA.unprepend, ([z, zs]) => go(f(z)(acc))(zs))));
return go;
};
export const reduceRightWhile = (p) => (f) => (x) => flow(RA.reverse, reduceWhile(p)(f)(x));
export const minimum = flow(min, NEA.concatAll);
export const maximum = flow(max, NEA.concatAll);
export const zipAll = (xs) => (ys) => {
const zs = RA.zip(ys, xs);
const getRem = slice(RA.size(zs))(Number.POSITIVE_INFINITY);
const rest = pipe(ordNumber.compare(RA.size(ys), RA.size(xs)), orderingMatch(() => pipe(xs, getRem, RA.map(T.right)), constant(RA.empty), () => pipe(ys, getRem, RA.map(T.left))));
return pipe(zs, RA.map(([za, zb]) => T.both(za, zb)), RA.concat(rest));
};
export function filterA(F) {
return p => xs => RA.Witherable.wither(F)(xs, x => F.map(p(x), y => (y ? O.some(x) : O.none)));
}
export const extractAt = (i) => (xs) => pipe(xs, RA.lookup(i), O.map(x => [x, RA.unsafeDeleteAt(i, xs)]));
export const fromIterable = Array.from;
export function allM(M) {
return RA.reduce(M.of(true), (x, y) => M.chain(x, b => (b ? y : M.of(false))));
}
export function anyM(M) {
return RA.reduce(M.of(false), (x, y) => M.chain(x, b => (b ? M.of(true) : y)));
}
export const separateNE = (xs) => pipe(xs, RA.separate, ({ left, right }) => {
if (RA.isEmpty(left))
return T.right(right);
if (RA.isEmpty(right))
return T.left(left);
return T.both(left, right);
});