import { Nat, NatOf, Suc, Zero, suc, zero } from "./typeLevelNats"; type GenericFunction = (...x: never[]) => unknown; type Assume = T extends U ? T : U; abstract class TypeFunc { readonly _1?: Param; abstract new: (_: Arg) => Ret; } type Apply, _1> = ReturnType< (F & { readonly _1: _1; })["new"] >; interface GetPrev extends TypeFunc, N> { new: (arg: Suc) => N; } // nat-elim : (M : T -> U) -> (cz : M z) -> (sz : (n : N) -> M n -> M (suc n)) -> (n : N) -> M n // (M : T -> U) -> (cz : M z) -> (sz : (n : N) -> M n -> M (suc n)) -> (n : N) -> M n // interface ConstNat extends TypeFunc { new: (_: any) => Nat; } type NatElim0< M extends TypeFunc, ZCase, SCase extends TypeFunc< Nat, TypeFunc, Apply>> >, N > = /** --------------------------------------------------------------- */ N extends Zero // // if N matches Zero ? ZCase // return ZCase : N extends Suc // if N matches Suc(Prev) ? Apply< any /* TODO: */, any /* TODO: */, Apply< Nat, TypeFunc, Apply>>, SCase, Prev >, Apply > : never; /* export interface DoubleSuc extends TypeFunc { new: (arg: Assume) => Suc>; } */ interface ExampleM extends TypeFunc { new: ( arg: Nat ) => typeof arg extends Suc ? ["x", ...Apply] : []; } export const _1: Apply = []; export const _2: Apply = [null]; /** * M is the type family being mapped over * M : (n : N) -> U * M zero = Nat */ interface DoubleNat_M extends TypeFunc { new: (arg: Nat) => Nat; /* typeof arg extends Suc ? Suc>> : Zero; */ } /** * DoubleNat_SCase_App1 is what happens after applying 1 arg to DoubleNat_SCase * (given n : N in the context) * SCase_App1 : (prev : M n) -> M (suc n) * SCase_App1 prev = prev + 2 */ interface DoubleNat_SCase_App1< M extends TypeFunc, Nat, any>, N extends Nat

, P = unknown > extends TypeFunc< Apply, Nat, M, N>, // (prev : M n) Apply>, Nat, M, Suc>, // -> M (suc n) Nat > { new: (prev: Assume>) => Suc>; } /** * This is the suc case for DoubleNat: * SCase : (n : N) -> (prev : M n) -> M (suc n) */ interface DoubleNat_SCase> extends TypeFunc> { new: (arg: Nat) => DoubleNat_SCase_App1; } export const _3: Apply< Nat, Nat, Apply, DoubleNat_SCase, NatOf<4>>, NatOf<4> > = suc(suc(suc(suc(suc(suc(zero)))))); function isNatOfFour>(_: T) {} /* 3 */ isNatOfFour(undefined as unknown as Suc>>); /* 4 */ isNatOfFour(undefined as unknown as Suc>>>); /* 5 */ isNatOfFour(undefined as unknown as Suc>>>>); interface DoubleNat extends TypeFunc { new: ( arg: Nat ) => NatElim0, typeof arg>; } type Two = Suc>; function isTwo(_: F) {} isTwo(suc(zero)); isTwo(suc(suc(zero))); isTwo(suc(suc(suc(zero)))); const realThree: Suc>> = suc(suc(suc(zero))); const realFour: Suc>>> = suc(suc(suc(suc(zero)))); function isFour>(_: F) {} isFour(realThree); isFour(realFour); /* interface NatElim< MRet, M extends TypeFunc, ZCase extends Apply, Z>, SCase extends TypeFunc > extends TypeFunc { _unused: (_1: ZCase, _2: SCase) => never; new: (arg: Assume) => Apply; } */ ///// type Length = T extends { length: infer L } ? L : never; type BuildTuple = T extends { length: L; } ? T : BuildTuple; type Add = Length< [...BuildTuple, ...BuildTuple] >; type Equals = { eq: [T1, T2] }; type Seven = Add<3, 4>; // 7 function isSeven(s: Seven) {} isSeven(6); isSeven(7); /// class Eq { private a: (_: A) => A; private b: (_: B) => B; private constructor() {} static refl(): Eq { return new Eq(); } } function isEqual1(_: Eq<3, 3>) {} isEqual1(Eq.refl()); function isEqual2(_: Eq<3, 4>) {} isEqual2(Eq.refl()); function isEqual3(_: Eq, 7>) {} isEqual3(Eq.refl()); function isEqual4(_: Eq, 8>) {} isEqual4(Eq.refl()); /// type Commutative = Eq, Add>; function comm(): Commutative { return Eq.refl(); }