UNPKG

fp-ts-std

Version:

The missing pseudo-standard library for fp-ts.

104 lines (103 loc) 5.44 kB
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); });