Skip to content

Instantly share code, notes, and snippets.

@gtkatakura
Last active January 11, 2019 00:38
Show Gist options
  • Save gtkatakura/4f5ec735a4747fb2b9d1f09cf3e5598e to your computer and use it in GitHub Desktop.
Save gtkatakura/4f5ec735a4747fb2b9d1f09cf3e5598e to your computer and use it in GitHub Desktop.
@gtkatakura
Copy link
Author

gtkatakura commented Jan 11, 2019

// Tuple operations Cons, Head, Tail

type Head<T> = T extends [infer U, ...unknown[]] ? U : never

type Tail<T> = T extends Array<any>
  ? ((...args: T) => never) extends ((a: any, ...args: infer R) => never)
    ? R
    : never
  : never

type Cons<T extends any[], H> = ((h: H, ...t: T) => any) extends ((...x: infer X) => any) ? X : never

// Generic lazy tuple reduction

interface Reduction<Base, In> {
  0: Base
  1: In
}

type Reduce<T extends Array<any>, R extends Reduction<any, any>> = R[T extends [] ? 0 : 1]

// Tuple reversal

interface ReverseRec<H extends Array<any>, T extends Array<any>>
  extends Reduction<H, Reduce<Tail<T>, ReverseRec<Cons<H, Head<T>>, Tail<T>>>> {}

type Reverse<T> = T extends Array<any> ? Reduce<T, ReverseRec<[], T>> : never

// Currying, finally

interface CurryRec<H, T extends Array<any>>
  extends Reduction<
  H,
  Reduce<
    Tail<T>,
    CurryRec<(arg: Head<T>) => H, Tail<T>>
  >
>{}

type Curry<F extends (...args: any[]) => any> = Reverse<Parameters<F>> extends infer R
  ? R extends any[]
    ? Reduce<R, CurryRec<ReturnType<F>, R>>
    : never
  : never

declare function curry<F extends (...args: any[]) => any>(f: F): Curry<F>
declare const f: (a: number, b: string, c: symbol, d: boolean, e: void) => boolean

const curried = curry(f) // (args_0: number) => (args_0: string) => (args_0: symbol) => (args_0: boolean) => (args_0: void) => boolean

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment