diff --git a/test.ts b/test.ts index a86845b..2c4d0dd 100644 --- a/test.ts +++ b/test.ts @@ -1,11 +1,11 @@ -import {} from "./typeLevelNats"; +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?: unknown; - new: (_: Arg) => Ret; +abstract class TypeFunc { + readonly _1?: Param; + abstract new: (_: Arg) => Ret; } type Apply, _1> = ReturnType< @@ -26,10 +26,6 @@ interface ConstNat extends TypeFunc { new: (_: any) => Nat; } -interface DoubleSuc extends TypeFunc { - new: (arg: Assume) => Suc>; -} - type NatElim0< M extends TypeFunc, ZCase, @@ -56,9 +52,91 @@ type NatElim0< > : never; -interface DoubleNat extends TypeFunc { - new: (arg: Nat) => NatElim0; +/* +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< @@ -70,15 +148,6 @@ interface NatElim< _unused: (_1: ZCase, _2: SCase) => never; new: (arg: Assume) => Apply; } - -type Two = S>; - -const realThree: S>> = S.s(); -const realFour: S>>> = S.s(); - -function isFour>(_: F) {} -isFour(realThree); -isFour(realFour); */ ///// diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..63d3866 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "strict": true, + "lib": ["esnext"], + "noUnusedLocals": false + } +} diff --git a/typeLevelNats.ts b/typeLevelNats.ts index 852af15..e8fe8b2 100644 --- a/typeLevelNats.ts +++ b/typeLevelNats.ts @@ -1,8 +1,9 @@ export type Zero = { tag: "Zero" }; export type Suc = { tag: "Suc"; prev: Prev }; +export type Nat

= Zero | Suc

; -const zero: Zero = { tag: "Zero" }; -function suc(p: Prev): Suc { +export const zero: Zero = { tag: "Zero" }; +export function suc(p: Prev): Suc { return { tag: "Suc", prev: p }; } @@ -27,22 +28,47 @@ type LengthOfTail = Length>; const _10: LengthOfTail<[3, 4, 5]> = 2; const _11: LengthOfTail<[3, 4, 5]> = 3; -type Nat = BuildTuple extends ["x", ...infer rest] - ? Suc>> +export type NatOf = BuildTuple extends [ + "x", + ...infer rest +] + ? Suc>> : Zero; + const _15: ["x"] extends ["x", ...infer _] ? "true" : "false" = "true"; const _16: ["x"] extends ["x", ...infer _] ? "true" : "false" = "false"; const _17: [] extends ["x", ...infer _] ? "true" : "false" = "true"; const _18: [] extends ["x", ...infer _] ? "true" : "false" = "false"; -const _1: Nat<0> = zero; +const _1: NatOf<0> = zero; -const _3: Nat<1> = suc(zero); // should pass -const _2: Nat<1> = zero; // should fail +const _3: NatOf<1> = suc(zero); // should pass +const _2: NatOf<1> = zero; // should fail -const _5: Nat<4> = suc(suc(suc(suc(zero)))); // should pass -const _4: Nat<4> = suc(suc(suc(zero))); // should fail +const _5: NatOf<4> = suc(suc(suc(suc(zero)))); // should pass +const _4: NatOf<4> = suc(suc(suc(zero))); // should fail + +export { + _1, + _2, + _3, + _4, + _5, + _6, + _7, + _8, + _9, + _10, + _11, + _12, + _13, + _14, + _15, + _16, + _17, + _18, +}; type RealNats = [ 0,