// @flow
export type Predicate = (a: A) => boolean;
export type Fn1 = (a: A, ...rest: Array) => B;
export type Fn2 = (a: A, b: B, ...rest: Array) => C;
export type Fn3 = (a: A, b: B, c: C, ...rest: Array) => D;
export type Fn4 = (a: A, b: B, c: C, d: D, ...rest: Array) => E;
export type Fn5 = (a: A, b: B, c: C, d: D, e: E, ...rest: Array) => F;
export type Fn6 = (a: A, b: B, c: C, d: D, e: E, f: F, ...rest: Array) => G;
export type Fn7 = (a: A, b: B, c: C, d: D, e: E, f: F, g: G, ...rest: Array) => H;
export type Fn8 = (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, ...rest: Array) => I;
export type Fn9 = (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, ...rest: Array) => L;
export type Endomorphism = Fn1;
declare function compose(bc: Fn1, ab: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function compose(cd: Fn1, bc: Fn1, ab: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function compose(de: Fn1, cd: Fn1, bc: Fn1, ab: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function compose(fe: Fn1, de: Fn1, cd: Fn1, bc: Fn1, ab: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function compose(fg: Fn1, fe: Fn1, de: Fn1, cd: Fn1, bc: Fn1, ab: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function compose(fh: Fn1, fg: Fn1, fe: Fn1, de: Fn1, cd: Fn1, bc: Fn1, ab: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function compose(fi: Fn1, fh: Fn1, fg: Fn1, fe: Fn1, de: Fn1, cd: Fn1, bc: Fn1, ab: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function compose(fj: Fn1, fi: Fn1, fh: Fn1, fg: Fn1, fe: Fn1, de: Fn1, cd: Fn1, bc: Fn1, ab: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function pipe(ab: Fn1, bc: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function pipe(ab: Fn1, bc: Fn1, cd: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function pipe(ab: Fn1, bc: Fn1, cd: Fn1, de: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function pipe(ab: Fn1, bc: Fn1, cd: Fn1, de: Fn1, ef: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function pipe(ab: Fn1, bc: Fn1, cd: Fn1, de: Fn1, ef: Fn1, fg: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function pipe(ab: Fn1, bc: Fn1, cd: Fn1, de: Fn1, ef: Fn1, fg: Fn1, gh: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function pipe(ab: Fn1, bc: Fn1, cd: Fn1, de: Fn1, ef: Fn1, fg: Fn1, gh: Fn1, hi: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
declare function pipe(ab: Fn1, bc: Fn1, cd: Fn1, de: Fn1, ef: Fn1, fg: Fn1, gh: Fn1, hi: Fn1, ij: Fn1, ...rest: Array): Fn1; // eslint-disable-line no-redeclare
export type CurriedFn2 =
& Fn1>
& Fn2;
export type CurriedFn3 =
& Fn1>
& Fn2>
& Fn3;
export type CurriedFn4 =
& Fn1>
& Fn2>
& Fn3>
& Fn4;
export type CurriedFn5 =
& Fn1>
& Fn2>
& Fn3>
& Fn4>
& Fn5;
declare function curry(f: Fn2): CurriedFn2; // eslint-disable-line no-redeclare
declare function curry(f: Fn3): CurriedFn3; // eslint-disable-line no-redeclare
declare function curry(f: Fn4): CurriedFn4; // eslint-disable-line no-redeclare
declare function curry(f: Fn5): CurriedFn5; // eslint-disable-line no-redeclare
// Flips the order of the arguments to a function of two arguments.
export function flip(f: (a: A, b: B) => C): (b: B, a: A) => C {
return (b, a) => f(a, b)
}
// Returns its first argument and ignores its second.
export function constant(a: A): (b: B) => A {
return () => a
}
// The `on` function is used to change the domain of a binary operator.
export function on(o: (x: B, y: B) => C, f: (a: A) => B): (x: A, y: A) => C {
return (x, y) => o(f(x), f(y))
}
export function compose(...fns) { // eslint-disable-line no-redeclare
const len = fns.length - 1
return x => {
let y = x
for (let i = len; i > -1; i--) {
y = fns[i].call(this, y)
}
return y
}
}
export function pipe(...fns) { // eslint-disable-line no-redeclare
const len = fns.length - 1
return x => {
let y = x
for (let i = 0; i <= len; i++) {
y = fns[i].call(this, y)
}
return y
}
}
function curried(f, length, acc) {
return function () {
const combined = acc.concat(Array.prototype.slice.call(arguments))
return combined.length >= length ? f.apply(this, combined) : curried(f, length, combined)
}
}
export function curry(f: Function) { // eslint-disable-line no-redeclare
return curried(f, f.length, [])
}