/** * @since 1.0.0 */ import type { TypeLambda } from "@fp-ts/core/HKT" // ------------------------------------------------------------------------------------- // type lambdas // ------------------------------------------------------------------------------------- /** * @category type lambdas * @since 1.0.0 */ export interface FunctionTypeLambda extends TypeLambda { readonly type: (a: this["In"]) => this["Target"] } /** * Tests if a value is a `function`. * * @param input - The value to test. * * @example * import { isFunction } from '@fp-ts/core/Predicate' * * assert.deepStrictEqual(isFunction(isFunction), true) * assert.deepStrictEqual(isFunction("function"), false) * * @category guards * @since 1.0.0 */ export const isFunction = (input: unknown): input is Function => typeof input === "function" /** * Creates a function that is both data-last and data-first. * * @since 1.0.0 */ export const dual = < DataLast extends (...args: Array) => any, DataFirst extends (...args: Array) => any >( dataFirstArity: Parameters["length"], body: DataFirst ): DataLast & DataFirst => { // @ts-expect-error return function() { if (arguments.length >= dataFirstArity) { // @ts-expect-error return body.apply(this, arguments) } return ((self: any) => body(self, ...arguments)) as any } } /** * Apply a function to a given value. * * @example * import { pipe, apply } from '@fp-ts/core/Function' * import { increment } from '@fp-ts/core/Number' * * assert.deepStrictEqual(pipe(2, apply(increment)), 3) * * @since 1.0.0 */ export const apply = (self: (a: A) => B) => (a: A): B => self(a) /** * A lazy argument * * @since 1.0.0 */ export interface LazyArg { (): A } /** * @example * import { FunctionN } from '@fp-ts/core/Function' * * export const sum: FunctionN<[number, number], number> = (a, b) => a + b * * @since 1.0.0 */ export interface FunctionN, B> { (...args: A): B } /** * @since 1.0.0 */ export const identity = (a: A): A => a /** * @since 1.0.0 */ export const unsafeCoerce: (a: A) => B = identity as any /** * Creates a constant value that never changes. * * This is useful when you want to pass a value to a higher-order function (a function that takes another function as its argument) * and want that inner function to always use the same value, no matter how many times it is called. * * @param value - The constant value to be returned * * @since 1.0.0 */ export const constant = (value: A): LazyArg => () => value /** * A thunk that returns always `true`. * * @since 1.0.0 */ export const constTrue: LazyArg = constant(true) /** * A thunk that returns always `false`. * * @since 1.0.0 */ export const constFalse: LazyArg = constant(false) /** * A thunk that returns always `null`. * * @since 1.0.0 */ export const constNull: LazyArg = constant(null) /** * A thunk that returns always `undefined`. * * @since 1.0.0 */ export const constUndefined: LazyArg = constant(undefined) /** * A thunk that returns always `void`. * * @since 1.0.0 */ export const constVoid: LazyArg = constUndefined /** * Reverses the order of arguments for a curried function. * * @param f -A curried function that takes multiple arguments. * * @example * import { flip } from '@fp-ts/core/Function' * * const f = (a: number) => (b: string) => a - b.length * * assert.deepStrictEqual(flip(f)('aaa')(2), -1) * * @since 1.0.0 */ export const flip = , B extends Array, C>( f: (...a: A) => (...b: B) => C ): ((...b: B) => (...a: A) => C) => (...b) => (...a) => f(...a)(...b) /** * Performs left-to-right function composition. The first argument may have any arity, the remaining arguments must be unary. * * @example * import { flow } from '@fp-ts/core/Function' * * const len = (s: string): number => s.length * const double = (n: number): number => n * 2 * * const f = flow(len, double) * * assert.deepStrictEqual(f('aaa'), 6) * * @see {@link pipe} * @since 1.0.0 */ export function flow, B>(ab: (...a: A) => B): (...a: A) => B export function flow, B, C>( ab: (...a: A) => B, bc: (b: B) => C ): (...a: A) => C export function flow, B, C, D>( ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D ): (...a: A) => D export function flow, 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, 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, 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, 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, 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, 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 } /** * Composes two functions, `ab` and `bc` into a single function that takes in an argument `a` of type `A` and returns a result of type `C`. * The result is obtained by first applying the `ab` function to `a` and then applying the `bc` function to the result of `ab`. * * @param ab - A function that maps from `A` to `B`. * @param bc - A function that maps from `B` to `C`. * * @example * import { compose } from '@fp-ts/core/Function' * * const inc = (n: number) => n + 1; * const square = (n: number) => n * n; * * assert.strictEqual(compose(inc, square)(2), 9); * * @since 1.0.0 */ export const compose: { (bc: (b: B) => C): (self: (a: A) => B) => (a: A) => C (self: (a: A) => B, bc: (b: B) => C): (a: A) => C } = dual(2, (ab: (a: A) => B, bc: (b: B) => C): (a: A) => C => flow(ab, bc)) /** * The `absurd` function is a stub for cases where a value of type `never` is encountered in your code, * meaning that it should be impossible for this code to be executed. * * This function is particularly useful in functional programming, where it's often necessary to specify that certain cases are impossible. * By calling `absurd`, you can ensure that the type system correctly reflects that a certain value should never occur. * * @since 1.0.0 */ export const absurd = (_: 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/core/Function' * * const add = tupled((x: number, y: number): number => x + y) * * assert.deepStrictEqual(add([1, 2]), 3) * * @since 1.0.0 */ export const tupled = , B>(f: (...a: A) => B): ((a: A) => B) => (a) => f(...a) /** * Inverse function of `tupled` * * @since 1.0.0 */ export const untupled = , B>(f: (a: A) => B): ((...a: A) => B) => (...a) => f(a) /** * Pipes the value of an expression into a pipeline of functions. * * @example * import { pipe } from '@fp-ts/core/Function' * * const len = (s: string): number => s.length * const double = (n: number): number => n * 2 * * assert.deepStrictEqual(pipe('aaa', len, double), 6) * * @see {@link flow} * @since 1.0.0 */ export function pipe(a: A): A export function pipe(a: A, ab: (a: A) => B): B export function pipe(a: A, ab: (a: A) => B, bc: (b: B) => C): C export function pipe(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D): D export function pipe( a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E ): E export function pipe( 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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 1.0.0 */ export const hole: () => T = absurd as any /** * The SK combinator, also known as the "S-K combinator" or "S-combinator", is a fundamental combinator in the * lambda calculus and the SKI combinator calculus. * * This function is useful for discarding the first argument passed to it and returning the second argument. * * @param _ - The first argument to be discarded. * @param b - The second argument to be returned. * * @example * import { SK } from '@fp-ts/core/Function'; * * assert.deepStrictEqual(SK(0, 'hello'), 'hello') * * @since 1.0.0 */ export const SK = (_: A, b: B): B => b