import { shift } from './array';
export interface Curried1 {
(a: a): z;
}
export interface Curried2 {
(a: a, b: b): z;
(a: a): Curried1;
}
export interface Curried3 {
(a: a, b: b, c: c): z;
(a: a, b: b): Curried1;
(a: a): Curried2;
}
export interface Curried4 {
(a: a, b: b, c: c, d: d): z;
(a: a, b: b, c: c): Curried1;
(a: a, b: b): Curried2;
(a: a): Curried3;
}
export interface Curried5 {
(a: a, b: b, c: c, d: d, e: e): z;
(a: a, b: b, c: c, d: d): Curried1;
(a: a, b: b, c: c): Curried2;
(a: a, b: b): Curried3;
(a: a): Curried4;
}
export interface Curry {
(f: (a: a) => z): Curried1;
(f: (a: a, b: b) => z): Curried2;
(f: (a: a, b: b, c: c) => z): Curried3;
(f: (a: a, b: b, c: c, d: d) => z): Curried4;
(f: (a: a, b: b, c: c, d: d, e: e) => z): Curried5;
}
export const curry: Curry = ((f: () => z) =>
curry_(f, f.length));
function curry_(f: (...xs: unknown[]) => unknown, arity: number, ...xs: unknown[]) {
let g: typeof f;
return xs.length < arity
? (...ys: unknown[]) => curry_(g ??= xs.length ? f.bind(undefined, ...xs) : f, arity - xs.length, ...ys)
: f(...xs);
}
interface Uncurry {
(f: (a: a) => (b: b) => (c: c) => (d: d) => (e: e) => z): (a: a, b: b, c: c, d: d, e: e) => z;
(f: (a: a) => (b: b) => (c: c) => (d: d) => z): (a: a, b: b, c: c, d: d) => z;
(f: (a: a) => (b: b) => (c: c) => z): (a: a, b: b, c: c) => z;
(f: (a: a) => (b: b) => z): (a: a, b: b) => z;
(f: (a: a) => z): (a: a) => z;
}
export const uncurry: Uncurry = (f: (...xs: any[]) => any) =>
uncurry_(f);
function uncurry_(f: (...xs: any[]) => any): any {
const arity = f.length;
return (...xs: any[]) =>
arity === 0 || xs.length <= arity
? f(...xs)
: uncurry_(f(...shift(xs, arity)[0]))(...xs);
}