Skip to content
Permalink
Latest commit 08b8ebf Sep 30, 2022 History
12 contributors

Users who have contributed to this file

@gcanti @thewilkybarkid @raveclassic @pbadenski @OliverJAsh @heka1024 @tani @vicrac @leemhenson @jskeate @cdimitroulas @bumbleblym
/**
* @since 2.0.0
*/
import { BooleanAlgebra } from './BooleanAlgebra'
import { Monoid } from './Monoid'
import { Ring } from './Ring'
import { Semigroup } from './Semigroup'
import { Semiring } from './Semiring'
// -------------------------------------------------------------------------------------
// instances
// -------------------------------------------------------------------------------------
/**
* @category instances
* @since 2.10.0
*/
export const getBooleanAlgebra =
<B>(B: BooleanAlgebra<B>) =>
<A = never>(): BooleanAlgebra<(a: A) => B> => ({
meet: (x, y) => (a) => B.meet(x(a), y(a)),
join: (x, y) => (a) => B.join(x(a), y(a)),
zero: () => B.zero,
one: () => B.one,
implies: (x, y) => (a) => B.implies(x(a), y(a)),
not: (x) => (a) => B.not(x(a))
})
/**
* Unary functions form a semigroup as long as you can provide a semigroup for the codomain.
*
* @example
* import { Predicate, getSemigroup } from 'fp-ts/function'
* import * as B from 'fp-ts/boolean'
*
* const f: Predicate<number> = (n) => n <= 2
* const g: Predicate<number> = (n) => n >= 0
*
* const S1 = getSemigroup(B.SemigroupAll)<number>()
*
* assert.deepStrictEqual(S1.concat(f, g)(1), true)
* assert.deepStrictEqual(S1.concat(f, g)(3), false)
*
* const S2 = getSemigroup(B.SemigroupAny)<number>()
*
* assert.deepStrictEqual(S2.concat(f, g)(1), true)
* assert.deepStrictEqual(S2.concat(f, g)(3), true)
*
* @category instances
* @since 2.10.0
*/
export const getSemigroup =
<S>(S: Semigroup<S>) =>
<A = never>(): Semigroup<(a: A) => S> => ({
concat: (f, g) => (a) => S.concat(f(a), g(a))
})
/**
* Unary functions form a monoid as long as you can provide a monoid for the codomain.
*
* @example
* import { Predicate } from 'fp-ts/Predicate'
* import { getMonoid } from 'fp-ts/function'
* import * as B from 'fp-ts/boolean'
*
* const f: Predicate<number> = (n) => n <= 2
* const g: Predicate<number> = (n) => n >= 0
*
* const M1 = getMonoid(B.MonoidAll)<number>()
*
* assert.deepStrictEqual(M1.concat(f, g)(1), true)
* assert.deepStrictEqual(M1.concat(f, g)(3), false)
*
* const M2 = getMonoid(B.MonoidAny)<number>()
*
* assert.deepStrictEqual(M2.concat(f, g)(1), true)
* assert.deepStrictEqual(M2.concat(f, g)(3), true)
*
* @category instances
* @since 2.10.0
*/
export const getMonoid = <M>(M: Monoid<M>): (<A = never>() => Monoid<(a: A) => M>) => {
const getSemigroupM = getSemigroup(M)
return <A>() => ({
concat: getSemigroupM<A>().concat,
empty: () => M.empty
})
}
/**
* @category instances
* @since 2.10.0
*/
export const getSemiring = <A, B>(S: Semiring<B>): Semiring<(a: A) => B> => ({
add: (f, g) => (x) => S.add(f(x), g(x)),
zero: () => S.zero,
mul: (f, g) => (x) => S.mul(f(x), g(x)),
one: () => S.one
})
/**
* @category instances
* @since 2.10.0
*/
export const getRing = <A, B>(R: Ring<B>): Ring<(a: A) => B> => {
const S = getSemiring<A, B>(R)
return {
add: S.add,
mul: S.mul,
one: S.one,
zero: S.zero,
sub: (f, g) => (x) => R.sub(f(x), g(x))
}
}
// -------------------------------------------------------------------------------------
// utils
// -------------------------------------------------------------------------------------
/**
* @since 2.11.0
*/
export const apply =
<A>(a: A) =>
<B>(f: (a: A) => B): B =>
f(a)
/**
* A *thunk*
*
* @since 2.0.0
*/
export interface Lazy<A> {
(): A
}
/**
* @example
* import { FunctionN } from 'fp-ts/function'
*
* export const sum: FunctionN<[number, number], number> = (a, b) => a + b
*
* @since 2.0.0
*/
export interface FunctionN<A extends ReadonlyArray<unknown>, B> {
(...args: A): B
}
/**
* @since 2.0.0
*/
export function identity<A>(a: A): A {
return a
}
/**
* @since 2.0.0
*/
export const unsafeCoerce: <A, B>(a: A) => B = identity as any
/**
* @since 2.0.0
*/
export function constant<A>(a: A): Lazy<A> {
return () => a
}
/**
* A thunk that returns always `true`.
*
* @since 2.0.0
*/
export const constTrue: Lazy<boolean> = /*#__PURE__*/ constant(true)
/**
* A thunk that returns always `false`.
*
* @since 2.0.0
*/
export const constFalse: Lazy<boolean> = /*#__PURE__*/ constant(false)
/**
* A thunk that returns always `null`.
*
* @since 2.0.0
*/
export const constNull: Lazy<null> = /*#__PURE__*/ constant(null)
/**
* A thunk that returns always `undefined`.
*
* @since 2.0.0
*/
export const constUndefined: Lazy<undefined> = /*#__PURE__*/ constant(undefined)
/**
* A thunk that returns always `void`.
*
* @since 2.0.0
*/
export const constVoid: Lazy<void> = constUndefined
/**
* Flips the arguments of a curried function.
*
* @example
* import { flip } from 'fp-ts/function'
*
* const f = (a: number) => (b: string) => a - b.length
*
* assert.strictEqual(flip(f)('aaa')(2), -1)
*
* @since 2.0.0
*/
export function flip<A, B, C>(f: (a: A) => (b: B) => C): (b: B) => (a: A) => C
/** @deprecated */
export function flip<A, B, C>(f: (a: A, b: B) => C): (b: B, a: A) => C
export function flip(f: Function): Function {
return (...args: Array<any>) => {
if (args.length > 1) {
return f(args[1], args[0])
}
return (a: any) => f(a)(args[0])
}
}
/**
* Performs left-to-right function composition. The first argument may have any arity, the remaining arguments must be unary.
*
* See also [`pipe`](#pipe).
*
* @example
* import { flow } from 'fp-ts/function'
*
* const len = (s: string): number => s.length
* const double = (n: number): number => n * 2
*
* const f = flow(len, double)
*
* assert.strictEqual(f('aaa'), 6)
*
* @since 2.0.0
*/
export function flow<A extends ReadonlyArray<unknown>, B>(ab: (...a: A) => B): (...a: A) => B
export function flow<A extends ReadonlyArray<unknown>, B, C>(ab: (...a: A) => B, bc: (b: B) => C): (...a: A) => C
export function flow<A extends ReadonlyArray<unknown>, B, C, D>(
ab: (...a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D
): (...a: A) => D
export function flow<A extends ReadonlyArray<unknown>, B, C, D, E>(
ab: (...a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E
): (...a: A) => E
export function flow<A extends ReadonlyArray<unknown>, B, C, D, E, F>(
ab: (...a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F
): (...a: A) => F
export function flow<A extends ReadonlyArray<unknown>, B, C, D, E, F, G>(
ab: (...a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G
): (...a: A) => G
export function flow<A extends ReadonlyArray<unknown>, B, C, D, E, F, G, H>(
ab: (...a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H
): (...a: A) => H
export function flow<A extends ReadonlyArray<unknown>, B, C, D, E, F, G, H, I>(
ab: (...a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H,
hi: (h: H) => I
): (...a: A) => I
export function flow<A extends ReadonlyArray<unknown>, B, C, D, E, F, G, H, I, J>(
ab: (...a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H,
hi: (h: H) => I,
ij: (i: I) => J
): (...a: A) => J
export function flow(
ab: Function,
bc?: Function,
cd?: Function,
de?: Function,
ef?: Function,
fg?: Function,
gh?: Function,
hi?: Function,
ij?: Function
): unknown {
switch (arguments.length) {
case 1:
return ab
case 2:
return function (this: unknown) {
return bc!(ab.apply(this, arguments))
}
case 3:
return function (this: unknown) {
return cd!(bc!(ab.apply(this, arguments)))
}
case 4:
return function (this: unknown) {
return de!(cd!(bc!(ab.apply(this, arguments))))
}
case 5:
return function (this: unknown) {
return ef!(de!(cd!(bc!(ab.apply(this, arguments)))))
}
case 6:
return function (this: unknown) {
return fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments))))))
}
case 7:
return function (this: unknown) {
return gh!(fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments)))))))
}
case 8:
return function (this: unknown) {
return hi!(gh!(fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments))))))))
}
case 9:
return function (this: unknown) {
return ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments)))))))))
}
}
return
}
/**
* @since 2.0.0
*/
export function tuple<T extends ReadonlyArray<any>>(...t: T): T {
return t
}
/**
* @since 2.0.0
*/
export function increment(n: number): number {
return n + 1
}
/**
* @since 2.0.0
*/
export function decrement(n: number): number {
return n - 1
}
/**
* @since 2.0.0
*/
export function absurd<A>(_: never): A {
throw new Error('Called `absurd` function which should be uncallable')
}
/**
* Creates a tupled version of this function: instead of `n` arguments, it accepts a single tuple argument.
*
* @example
* import { tupled } from 'fp-ts/function'
*
* const add = tupled((x: number, y: number): number => x + y)
*
* assert.strictEqual(add([1, 2]), 3)
*
* @since 2.4.0
*/
export function tupled<A extends ReadonlyArray<unknown>, B>(f: (...a: A) => B): (a: A) => B {
return (a) => f(...a)
}
/**
* Inverse function of `tupled`
*
* @since 2.4.0
*/
export function untupled<A extends ReadonlyArray<unknown>, B>(f: (a: A) => B): (...a: A) => B {
return (...a) => f(a)
}
/**
* Pipes the value of an expression into a pipeline of functions.
*
* See also [`flow`](#flow).
*
* @example
* import { pipe } from 'fp-ts/function'
*
* const len = (s: string): number => s.length
* const double = (n: number): number => n * 2
*
* // without pipe
* assert.strictEqual(double(len('aaa')), 6)
*
* // with pipe
* assert.strictEqual(pipe('aaa', len, double), 6)
*
* @since 2.6.3
*/
export function pipe<A>(a: A): A
export function pipe<A, B>(a: A, ab: (a: A) => B): B
export function pipe<A, B, C>(a: A, ab: (a: A) => B, bc: (b: B) => C): C
export function pipe<A, B, C, D>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D): D
export function pipe<A, B, C, D, E>(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E): E
export function pipe<A, B, C, D, E, F>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F
): F
export function pipe<A, B, C, D, E, F, G>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G
): G
export function pipe<A, B, C, D, E, F, G, H>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H
): H
export function pipe<A, B, C, D, E, F, G, H, I>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H,
hi: (h: H) => I
): I
export function pipe<A, B, C, D, E, F, G, H, I, J>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H,
hi: (h: H) => I,
ij: (i: I) => J
): J
export function pipe<A, B, C, D, E, F, G, H, I, J, K>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H,
hi: (h: H) => I,
ij: (i: I) => J,
jk: (j: J) => K
): K
export function pipe<A, B, C, D, E, F, G, H, I, J, K, L>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H,
hi: (h: H) => I,
ij: (i: I) => J,
jk: (j: J) => K,
kl: (k: K) => L
): L
export function pipe<A, B, C, D, E, F, G, H, I, J, K, L, M>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H,
hi: (h: H) => I,
ij: (i: I) => J,
jk: (j: J) => K,
kl: (k: K) => L,
lm: (l: L) => M
): M
export function pipe<A, B, C, D, E, F, G, H, I, J, K, L, M, N>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H,
hi: (h: H) => I,
ij: (i: I) => J,
jk: (j: J) => K,
kl: (k: K) => L,
lm: (l: L) => M,
mn: (m: M) => N
): N
export function pipe<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H,
hi: (h: H) => I,
ij: (i: I) => J,
jk: (j: J) => K,
kl: (k: K) => L,
lm: (l: L) => M,
mn: (m: M) => N,
no: (n: N) => O
): O
export function pipe<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H,
hi: (h: H) => I,
ij: (i: I) => J,
jk: (j: J) => K,
kl: (k: K) => L,
lm: (l: L) => M,
mn: (m: M) => N,
no: (n: N) => O,
op: (o: O) => P
): P
export function pipe<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H,
hi: (h: H) => I,
ij: (i: I) => J,
jk: (j: J) => K,
kl: (k: K) => L,
lm: (l: L) => M,
mn: (m: M) => N,
no: (n: N) => O,
op: (o: O) => P,
pq: (p: P) => Q
): Q
export function pipe<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H,
hi: (h: H) => I,
ij: (i: I) => J,
jk: (j: J) => K,
kl: (k: K) => L,
lm: (l: L) => M,
mn: (m: M) => N,
no: (n: N) => O,
op: (o: O) => P,
pq: (p: P) => Q,
qr: (q: Q) => R
): R
export function pipe<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H,
hi: (h: H) => I,
ij: (i: I) => J,
jk: (j: J) => K,
kl: (k: K) => L,
lm: (l: L) => M,
mn: (m: M) => N,
no: (n: N) => O,
op: (o: O) => P,
pq: (p: P) => Q,
qr: (q: Q) => R,
rs: (r: R) => S
): S
export function pipe<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T>(
a: A,
ab: (a: A) => B,
bc: (b: B) => C,
cd: (c: C) => D,
de: (d: D) => E,
ef: (e: E) => F,
fg: (f: F) => G,
gh: (g: G) => H,
hi: (h: H) => I,
ij: (i: I) => J,
jk: (j: J) => K,
kl: (k: K) => L,
lm: (l: L) => M,
mn: (m: M) => N,
no: (n: N) => O,
op: (o: O) => P,
pq: (p: P) => Q,
qr: (q: Q) => R,
rs: (r: R) => S,
st: (s: S) => T
): T
export function pipe(
a: unknown,
ab?: Function,
bc?: Function,
cd?: Function,
de?: Function,
ef?: Function,
fg?: Function,
gh?: Function,
hi?: Function
): unknown {
switch (arguments.length) {
case 1:
return a
case 2:
return ab!(a)
case 3:
return bc!(ab!(a))
case 4:
return cd!(bc!(ab!(a)))
case 5:
return de!(cd!(bc!(ab!(a))))
case 6:
return ef!(de!(cd!(bc!(ab!(a)))))
case 7:
return fg!(ef!(de!(cd!(bc!(ab!(a))))))
case 8:
return gh!(fg!(ef!(de!(cd!(bc!(ab!(a)))))))
case 9:
return hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(a))))))))
default: {
let ret = arguments[0]
for (let i = 1; i < arguments.length; i++) {
ret = arguments[i](ret)
}
return ret
}
}
}
/**
* Type hole simulation
*
* @since 2.7.0
*/
export const hole: <T>() => T = absurd as any
/**
* @since 2.11.0
*/
export const SK = <A, B>(_: A, b: B): B => b
// -------------------------------------------------------------------------------------
// deprecated
// -------------------------------------------------------------------------------------
/**
* Use `Refinement` module instead.
*
* @category zone of death
* @since 2.0.0
* @deprecated
*/
export interface Refinement<A, B extends A> {
(a: A): a is B
}
/**
* Use `Predicate` module instead.
*
* @category zone of death
* @since 2.0.0
* @deprecated
*/
export interface Predicate<A> {
(a: A): boolean
}
/**
* Use `Predicate` module instead.
*
* @category zone of death
* @since 2.0.0
* @deprecated
*/
export function not<A>(predicate: Predicate<A>): Predicate<A> {
return (a) => !predicate(a)
}
/**
* Use `Endomorphism` module instead.
*
* @category zone of death
* @since 2.0.0
* @deprecated
*/
export interface Endomorphism<A> {
(a: A): A
}
/**
* Use `Endomorphism` module instead.
*
* @category zone of death
* @since 2.10.0
* @deprecated
*/
export const getEndomorphismMonoid = <A = never>(): Monoid<Endomorphism<A>> => ({
concat: (first, second) => flow(first, second),
empty: identity
})