UNPKG

fp-ts-std

Version:

The missing pseudo-standard library for fp-ts.

106 lines (105 loc) 5.4 kB
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); });