├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── src ├── Bool.ts ├── Nat.ts ├── Vector.ts └── index.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atennapel/ts-typelevel-computation/1615daeb20f8e03c69e44c91ad613fe4c312f47e/.gitignore -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ts-typelevel-computation 2 | 3 | ```typescript 4 | // perform computations on the type level 5 | // includes: 6 | // Boolean: not, and, or, if 7 | // Nat: +, -, *, /, %, sqrt, log2, gcd and comparisons 8 | // Vector: mapping and appending 9 | 10 | type Test = Sqrt<_10>; // Test === 3 11 | 12 | const vec = cons(1, cons(2, cons(3, nil()))); // length is inferred to be 3 13 | const mapped = vec.map(x => x + 1); // length stays 3 14 | 15 | const vecDoubled = vec.append(vec); // length is 6 16 | ``` 17 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-typelevel-computation", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/node": { 8 | "version": "10.12.2", 9 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.2.tgz", 10 | "integrity": "sha512-53ElVDSnZeFUUFIYzI8WLQ25IhWzb6vbddNp8UHlXQyU0ET2RhV5zg0NfubzU7iNMh5bBXb0htCzfvrSVNgzaQ==", 11 | "dev": true 12 | }, 13 | "typescript": { 14 | "version": "3.1.6", 15 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.6.tgz", 16 | "integrity": "sha512-tDMYfVtvpb96msS1lDX9MEdHrW4yOuZ4Kdc4Him9oU796XldPYF/t2+uKoX0BBa0hXXwDlqYQbXY5Rzjzc5hBA==", 17 | "dev": true 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-typelevel-computation", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc", 8 | "index": "node build/src/index.js", 9 | "buildindex": "npm run build && npm run index" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "@types/node": "^10.12.2", 15 | "typescript": "^3.1.5" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Bool.ts: -------------------------------------------------------------------------------- 1 | export type Not = 2 | B extends true ? false : 3 | B extends false ? true : 4 | never; 5 | 6 | export type And = 7 | A extends false ? false : 8 | A extends true ? B : 9 | never; 10 | 11 | export type Or = 12 | A extends true ? true : 13 | A extends false ? B : 14 | never; 15 | 16 | export type If = 17 | C extends true ? A : 18 | C extends false ? B : 19 | never; 20 | -------------------------------------------------------------------------------- /src/Nat.ts: -------------------------------------------------------------------------------- 1 | import { Not } from './Bool'; 2 | 3 | // natural numbers 4 | export interface Z { tag: 'Z' } 5 | export interface S { tag: 'S'; val: N } 6 | 7 | export type Inc = S; 8 | export type Dec = N extends Z ? Z : N extends S ? M : never; 9 | 10 | // equality and comparison 11 | type Eq$ = 12 | A extends Z ? (B extends Z ? { val: true } : { val: false }) : 13 | A extends S ? (B extends S ? { val: Eq } : { val: false }) : 14 | never; 15 | export type Eq = Eq$['val']; 16 | 17 | type Leq$ = 18 | A extends Z ? { val: true } : 19 | B extends Z ? { val: false } : 20 | A extends S ? 21 | (B extends S ? { val: Leq } : never) : 22 | never; 23 | export type Leq = Leq$['val']; 24 | 25 | export type Lt = Leq, B>; 26 | export type Geq = Not>; 27 | export type Gt = Not>; 28 | 29 | type Compare$ = 30 | A extends Z ? 31 | (B extends Z ? { val: 0 } : 32 | B extends S ? { val: -1 } : never) : 33 | A extends S ? 34 | (B extends Z ? { val: 1 } : 35 | B extends S ? { val: Compare } : never) : 36 | never; 37 | export type Compare = Compare$['val']; 38 | 39 | // max and min 40 | type Max$ = 41 | A extends Z ? { val: B } : 42 | A extends S ? 43 | (B extends Z ? { val: A } : 44 | B extends S ? { val: S> }: never) : 45 | never; 46 | export type Max = Max$['val']; 47 | 48 | type Min$ = 49 | A extends Z ? { val: Z } : 50 | A extends S ? 51 | (B extends Z ? { val: Z } : 52 | B extends S ? { val: S> }: never) : 53 | never; 54 | export type Min = Min$['val']; 55 | 56 | // even and odd 57 | type Even$ = 58 | N extends Z ? { val: true } : 59 | N extends S ? 60 | (M extends Z ? { val: false} : 61 | M extends S ? { val: Even }: 62 | { val: never }) : 63 | never; 64 | export type Even = Even$['val']; 65 | 66 | export type Odd = Not>; 67 | 68 | // addition and subtraction 69 | type Add$ = 70 | A extends Z ? { val: B } : 71 | A extends S ? { val: S> } : 72 | never; 73 | export type Add = Add$['val']; 74 | 75 | type Sub$ = 76 | B extends Z ? { val: A } : 77 | { val: Sub, Dec> }; 78 | export type Sub = Sub$['val']; 79 | 80 | // multiplication, power, division and mod 81 | type Mul$ = 82 | A extends Z ? { val: Z } : 83 | A extends S ? { val: Add> } : 84 | never; 85 | export type Mul = Mul$['val']; 86 | 87 | type Pow$ = 88 | B extends Z ? { val: S } : 89 | B extends S ? { val: Mul> } : 90 | never; 91 | export type Pow = Pow$['val']; 92 | 93 | type DivMod$ = 94 | X extends Z ? { val: [Q, U] } : 95 | X extends S ? 96 | (U extends Z ? { val: DivMod, Y> } : 97 | U extends S ? { val: DivMod } : 98 | never) : 99 | never; 100 | export type DivMod = DivMod$['val']; 101 | 102 | export type Div = 103 | Y extends Z ? Z : 104 | Y extends S ? DivMod[0] : 105 | never; 106 | 107 | export type Mod = 108 | Y extends Z ? Z : 109 | Y extends S ? Sub[1]> : 110 | never; 111 | 112 | // double, half 113 | export type Double = Mul>>; 114 | export type Half = Div>>; 115 | 116 | // square and gcd 117 | export type Square = Mul; 118 | 119 | type GCD$ = 120 | A extends Z ? { val: B } : 121 | A extends S ? { val: GCD, A> } : 122 | never; 123 | export type GCD = GCD$['val']; 124 | 125 | // square root 126 | type SqrtIter$ = 127 | K extends Z ? { val : P } : 128 | K extends S ? 129 | (R extends Z ? { val: SqrtIter, S>, S>> } : 130 | R extends S ? { val: SqrtIter } : 131 | { val: never }) : 132 | never; 133 | type SqrtIter = SqrtIter$['val']; 134 | 135 | export type Sqrt = SqrtIter; 136 | 137 | // log2 138 | type Log2Iter$ = 139 | K extends Z ? { val : P } : 140 | K extends S ? 141 | (R extends Z ? { val: Log2Iter, S, Q> } : 142 | R extends S ? { val: Log2Iter, R$> } : 143 | { val: never }) : 144 | never; 145 | type Log2Iter = Log2Iter$['val']; 146 | 147 | export type Log2 = Log2Iter, Z, S, Z>; 148 | 149 | // some numbers 150 | export type _0 = Z; 151 | export type _1 = S<_0>; 152 | export type _2 = S<_1>; 153 | export type _3 = S<_2>; 154 | export type _4 = S<_3>; 155 | export type _5 = S<_4>; 156 | export type _6 = S<_5>; 157 | export type _7 = S<_6>; 158 | export type _8 = S<_7>; 159 | export type _9 = S<_8>; 160 | export type _10 = S<_9>; 161 | -------------------------------------------------------------------------------- /src/Vector.ts: -------------------------------------------------------------------------------- 1 | import { Z, S, Add } from './Nat'; 2 | 3 | export default abstract class Vector { 4 | 5 | abstract toString(): string; 6 | 7 | abstract map(fn: (val: T) => R): Vector; 8 | 9 | abstract append(that: Vector): Vector, T>; 10 | 11 | abstract toArray(): T[]; 12 | 13 | } 14 | 15 | export class Nil extends Vector { 16 | 17 | toString() { 18 | return 'Nil'; 19 | } 20 | 21 | map(fn: (val: T) => R): Vector { 22 | return this as any; 23 | } 24 | 25 | append(that: Vector): Vector { 26 | return that; 27 | } 28 | 29 | toArray(): T[] { 30 | return []; 31 | } 32 | 33 | } 34 | 35 | export class Cons extends Vector, T> { 36 | 37 | constructor( 38 | public readonly head: T, 39 | public readonly tail: Vector, 40 | ) { super() } 41 | 42 | toString() { 43 | return `Cons(${this.head}, ${this.tail})`; 44 | } 45 | 46 | map(fn: (val: T) => R): Vector, R> { 47 | return new Cons(fn(this.head), this.tail.map(fn)); 48 | } 49 | 50 | append(that: Vector): Vector, T> { 51 | return new Cons(this.head, this.tail.append(that)); 52 | } 53 | 54 | toArray(): T[] { 55 | return [this.head].concat(this.tail.toArray()); 56 | } 57 | 58 | } 59 | 60 | export const nil = (): Vector => new Nil(); 61 | export const cons = (head: T, tail: Vector): Vector, T> => new Cons(head, tail); 62 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { _10, Sqrt } from './Nat'; 2 | import { nil, cons } from './Vector'; 3 | 4 | type Test = Sqrt<_10>; // Test === 3 5 | 6 | const vec = cons(1, cons(2, cons(3, nil()))); // length is inferred to be 3 7 | const mapped = vec.map(x => x + 1); // length stays 3 8 | 9 | const vecDoubled = vec.append(vec); // length is 6 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2015", 5 | "rootDir": "./", 6 | "outDir": "build", 7 | "noImplicitAny": true, 8 | "noImplicitReturns": true, 9 | "noImplicitThis": true, 10 | "strictNullChecks": true, 11 | "types": ["node"], 12 | "typeRoots": [ "node_modules/@types" ] 13 | }, 14 | "include:": [ 15 | "src/**/*.ts" 16 | ], 17 | "exclude": [ 18 | "node_modules" 19 | ] 20 | } 21 | --------------------------------------------------------------------------------