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); }