fp-ts-std
Version:
The missing pseudo-standard library for fp-ts.
106 lines (105 loc) • 5.4 kB
JavaScript
import * as A from "fp-ts/Array";
import { reduceM } from "fp-ts/Foldable";
import { concatAll } from "fp-ts/Monoid";
import * as NEA from "fp-ts/NonEmptyArray";
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 R from "fp-ts/Record";
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 => A.elem(eq)(y)(xs);
export const none = flow(not, p => A.every(p));
export const join = (x) => invoke("join")([x]);
export const getDisorderedEq = (ordA) => ({
equals: (xs, ys) => {
const sort = A.sort(ordA);
return A.getEq(ordA).equals(sort(xs), sort(ys));
},
});
export const pluckFirst = (p) => (xs) => pipe(A.findIndex(p)(xs), O.fold(constant([O.none, xs]), i => [
O.some(xs[i]),
A.unsafeDeleteAt(i, xs),
]));
export const upsert = (eqA) => (x) => (ys) => pipe(A.findIndex(y => eqA.equals(x, y))(ys), O.map(i => A.unsafeUpdateAt(i, x, ys)), O.chain(NEA.fromArray), O.getOrElse(() => A.append(x)(ys)));
export const insertMany = (i) => (xs) => (ys) => pipe(xs, A.reverse, reduceM(O.Monad, A.Foldable)(ys, (zs, x) => pipe(zs, A.insertAt(i, x))), O.chain(NEA.fromArray));
export const dropRepeats = eq => xs => pipe(xs, A.filterWithIndex((i, x) => i === 0 || !eq.equals(x, xs[i - 1])));
export const startsWith = (eq) => (start) => flow(A.takeLeft(start.length), xs => A.getEq(eq).equals(xs, start));
export const endsWith = (eq) => (end) => flow(A.takeRight(end.length), xs => A.getEq(eq).equals(xs, end));
export const without = (eq) => (xs) => A.filter(y => !A.elem(eq)(y)(xs));
export const cartesian = (xs) => (ys) => pipe(xs, A.chain(x => pipe(ys, A.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)(A.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) => A.filter(not(f));
export const moveFrom = (from) => (to) => (xs) => from >= xs.length || to >= xs.length
? O.none
: from === to
? O.some(xs)
: pipe(xs, A.lookup(from), O.chain(x => pipe(A.deleteAt(from)(xs), O.chain(A.insertAt(to, x)))));
export const moveTo = flip(moveFrom);
export const countBy = (f) => (xs) => R.fromFoldableMap(MonoidSum, A.Foldable)(xs, x => [f(x), 1]);
export const dropRightWhile = (f) => flow(A.reverse, A.dropLeftWhile(f), A.reverse);
export const dropAt = (i) => (n) => (xs) => pipe(A.isOutOfBound(i, xs), B.fold(() => pipe(A.copy(xs), ys => {
ys.splice(i, n);
return ys;
}, O.some), constant(O.none)));
export const transpose = (xs) => {
if (A.isEmpty(xs))
return [];
if (A.isEmpty(xs[0]))
return transpose(A.dropLeft(1)(xs));
const [[y, ...ys], ...yss] = xs;
const zs = [y, ...A.filterMap(A.head)(yss)];
const zss = [ys, ...A.map(A.dropLeft(1))(yss)];
return [zs, ...transpose(zss)];
};
export const takeRightWhile = (f) => flow(A.reverse, A.takeLeftWhile(f), A.reverse);
export const symmetricDifference = (eq) => (xs) => ys => A.getMonoid().concat(A.difference(eq)(ys)(xs), A.difference(eq)(xs)(ys));
export const reduceWhile = (p) => (f) => {
const go = (acc) => (ys) => pipe(NEA.fromArray(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(A.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 = A.zip(ys, xs);
const getRem = slice(A.size(zs))(Number.POSITIVE_INFINITY);
const rest = pipe(ordNumber.compare(A.size(ys), A.size(xs)), orderingMatch(() => pipe(xs, getRem, A.map(T.right)), constant(A.empty), () => pipe(ys, getRem, A.map(T.left))));
return pipe(zs, A.map(([za, zb]) => T.both(za, zb)), A.concat(rest));
};
export function filterA(F) {
return p => xs => A.Witherable.wither(F)(xs, x => F.map(p(x), y => (y ? O.some(x) : O.none)));
}
export const extractAt = (i) => (xs) => pipe(xs, A.lookup(i), O.map(x => [x, A.unsafeDeleteAt(i, xs)]));
export const fromIterable = Array.from;
export const fromReadonly = RA.toArray;
export const toReadonly = RA.fromArray;
export function allM(M) {
return A.reduce(M.of(true), (x, y) => M.chain(x, b => (b ? y : M.of(false))));
}
export function anyM(M) {
return A.reduce(M.of(false), (x, y) => M.chain(x, b => (b ? M.of(true) : y)));
}
export const separateNE = (xs) => pipe(xs, A.separate, ({ left, right }) => {
if (A.isEmpty(left))
return T.right(right);
if (A.isEmpty(right))
return T.left(left);
return T.both(left, right);
});