import { Tail, Reverse } from '../type'; import { unshift } from '../array'; export type HList = as extends readonly [] ? HNil : HCons; export function HList(...as: as): HList; export function HList(...as: as): HList { return as.reduceRight>((node, a) => node.add(a), HNil as any); } type HNil = typeof HNil; const HNil = new class HNil { public add(a: a): HCons<[a]> { return new HCons(a, this); } public reverse(): [] { return []; } public tuple(): [] { return []; } }(); class HCons { constructor( public readonly head: as[0], public readonly tail: as extends readonly [unknown, unknown, ...unknown[]] ? HCons> : HNil, ) { } public add(a: a): HCons<[a, ...as]> { // @ts-ignore return new HCons(a, this); } public modify(f: (a: as[0]) => a): HCons<[a, ...Tail]> { // @ts-ignore return this.tail.add(f(this.head)); } public fold(this: HCons<[unknown, unknown, ...unknown[]]>, f: (l: as[0], r: as[1]) => a): HCons<[a, ...Tail>]> { // @ts-ignore return this.tail.modify(r => f(this.head, r)); } public unfold(f: (a: as[0]) => a): HCons<[a, ...as]> { // @ts-ignore return this.add(f(this.head)); } public reverse(): Reverse { return this.tuple().reverse() as Reverse; } public tuple(): as { return unshift([this.head], this.tail.tuple()) as as; } }