refactor: Explore final patterns for runtime typing with ts-macros
The idea is to have a single macro which lets you reflect multiple implementations. That's provided in this commit. However, there is a hitch with implementations that have no dependencies: the reflectedType property did not exist on the Signature type. However, if you add it, then the Signature type becomes opaque, so we would have to look up signatures; but that appears to be tricky, as there doesn't seem to be a way to reflect the full generic type of the Signatures interface. So this commit provides three example resolutions: (A) Export a type RTT and all no-dependency implementations have to intersect with RTT (see 'add' in number/arithmetic.ts) (B) Write no-dependency implementations as functions of no arguments (representing no dependencies passed in) returning the actual implementation (see 'subtract' in number/arithmetic.ts) (C) Make a special DSignature<> generic type (short for "Direct Signature" used only (and always) for implementations with no dependencies, and a matching $Dreflect!() macro for generating their type info. Of course, there may be other possibilities I haven't thought of. But we need to pick one. I don't think it matters _too_ much, since there only a small fraction of all implementations have no dependencies.
This commit is contained in:
parent
49b1332917
commit
ebe7cf831e
@ -2,7 +2,7 @@ import {Complex} from './type.js'
|
||||
import type {
|
||||
Dependencies, Signature, Returns, RealType, AliasOf
|
||||
} from '../interfaces/type.js'
|
||||
import {$reflecType} from '../interfaces/type.js'
|
||||
import {$reflect} from '../interfaces/type.js'
|
||||
|
||||
declare module "../interfaces/type" {
|
||||
interface Signatures<T> {
|
||||
@ -82,8 +82,7 @@ export const sqrt =
|
||||
addTR: Signature<'addReal', T>,
|
||||
addRR: Signature<'add', RealType<T>>,
|
||||
addCR: Signature<'addReal', Complex<T>>
|
||||
}):
|
||||
Signature<'sqrt', Complex<T>> =>
|
||||
}): Signature<'sqrt', Complex<T>> =>
|
||||
z => {
|
||||
const myabs = dep.conservativeSqrt(dep.absquare(z))
|
||||
const r = dep.re(z)
|
||||
@ -98,4 +97,4 @@ export const sqrt =
|
||||
const denom = dep.conservativeSqrt(denomsq)
|
||||
return dep.divideReal(num, denom)
|
||||
}
|
||||
$reflecType!(sqrt)
|
||||
$reflect!([sqrt])
|
||||
|
@ -1,7 +1,9 @@
|
||||
import type {Dependencies, Signature} from '../interfaces/type.js'
|
||||
import {$reflect} from '../interfaces/type.js'
|
||||
|
||||
export const square = $reflect!('square',
|
||||
<T>(dep: Dependencies<'multiply', T>) => (z:T) => dep.multiply(z, z))
|
||||
export const square =
|
||||
<T>(dep: Dependencies<'multiply', T>): Signature<'square', T> =>
|
||||
z => dep.multiply(z, z)
|
||||
// z => dep.fooBar(z, z) // fails as desired
|
||||
// z => dep.multiply(z, 'foo') // still fails as desired
|
||||
$reflect!([square])
|
||||
|
22
src/index.ts
22
src/index.ts
@ -1,12 +1,20 @@
|
||||
import {inspect} from 'node:util'
|
||||
import {Dispatcher} from './core/Dispatcher.js'
|
||||
import {Signatures, Deps} from './interfaces/type.js'
|
||||
import {$$typeToString} from 'ts-macros'
|
||||
import * as Specifications from './all.js'
|
||||
|
||||
class Placeholder {}
|
||||
const allSignatures =
|
||||
$$typeToString!<Deps<Signatures<Placeholder>>>(true, false, true)
|
||||
|
||||
console.log('Found signatures', allSignatures)
|
||||
|
||||
export default new Dispatcher(Specifications)
|
||||
|
||||
import {Complex} from './Complex/type.js'
|
||||
import {absquare as absquare_complex} from './Complex/arithmetic.js'
|
||||
import { parseReflectedType, split } from './core/parseReflectedType.js'
|
||||
import {parseReflectedType} from './core/parseReflectedType.js'
|
||||
|
||||
const mockRealAdd = (a: number, b: number) => a+b
|
||||
const mockComplexAbsquare = (z: Complex<number>) => z.re*z.re + z.im*z.im
|
||||
@ -36,7 +44,11 @@ console.log('Result of sqrt(-4)=', sqrt(-4))
|
||||
console.log()
|
||||
console.log('1) NUMBER SQRT')
|
||||
console.log(`1.1) REFLECTED TYPE: "${Specifications.numbers.sqrt.reflectedType}"`)
|
||||
console.log('1.2) PARSED TYPE:', inspect(parseReflectedType('sqrt', Specifications.numbers.sqrt.reflectedType), { depth: null, colors: true }))
|
||||
console.log(
|
||||
'1.2) PARSED TYPE:',
|
||||
inspect(
|
||||
parseReflectedType('sqrt', Specifications.numbers.sqrt.reflectedType),
|
||||
{ depth: null, colors: true }))
|
||||
|
||||
console.log()
|
||||
console.log('2) GENERIC SQUARE')
|
||||
@ -47,9 +59,3 @@ console.log()
|
||||
console.log('3) COMPLEX SQRT')
|
||||
console.log(`1.1) REFLECTED TYPE: "${Specifications.complex.sqrt.reflectedType}"`)
|
||||
console.log('3.2) PARSED TYPE:', inspect(parseReflectedType('sqrt', Specifications.complex.sqrt.reflectedType), { depth: null, colors: true }))
|
||||
|
||||
// FIXME: cleanup
|
||||
// console.log()
|
||||
// console.log('split', split('hello**world**how**are**you', '**'))
|
||||
// console.log('split', split('hello(test**world)**how**are**you', '**'))
|
||||
// console.log('split', split('<T>(dep: { multiply: (a: T, b: T) => T; }) => (z: T) => T', '=>'))
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {$$typeToString, $$ident, $$define} from 'ts-macros'
|
||||
import {$$typeToString} from 'ts-macros'
|
||||
|
||||
/*****
|
||||
* Every typocomath type has some associated types; they need
|
||||
@ -74,25 +74,23 @@ export interface Signatures<T> {
|
||||
|
||||
type SignatureKey<T> = keyof Signatures<T>
|
||||
|
||||
export type Signature<Name extends SignatureKey<T>, T> = Signatures<T>[Name]
|
||||
export type Signature<Name extends SignatureKey<T>, T> =
|
||||
Signatures<T>[Name]
|
||||
export type DSignature<Name extends SignatureKey<T>, T> =
|
||||
Signatures<T>[Name] & {reflectedType?: string, actualType?: Signatures<T>[Name]}
|
||||
export type Returns<Name extends SignatureKey<T>, T> = ReturnType<Signatures<T>[Name]>
|
||||
type Deps<T> = T extends unknown ? { [K in keyof T]: T[K] } : never;
|
||||
export type Deps<T> = T extends unknown ? { [K in keyof T]: T[K] } : never;
|
||||
export type Dependencies<Name extends SignatureKey<T>, T> = Deps<{[K in Name]: Signature<K, T>}>
|
||||
|
||||
export type AliasOf<Name extends string, T> = T & {aliasOf?: Name}
|
||||
|
||||
// For defining implementations with type reflection
|
||||
export function $reflect<Impl>(name: string, expr: Impl) : Impl & { reflectedType: string} {
|
||||
$$define!(name, expr, false, false);
|
||||
$$ident!(name).reflectedType = $$typeToString!<Impl>(true, false, true);
|
||||
return $$ident!(name)
|
||||
}
|
||||
|
||||
export function $reflecType<Impl>(expr: Impl) {
|
||||
expr.reflectedType = $$typeToString!<Impl>(true, false, true);
|
||||
}
|
||||
|
||||
export function $reflecTypes<ImplTuple>(tup: ImplTuple) {
|
||||
export function $reflect<ImplTuple>(tup: ImplTuple) {
|
||||
+[[tup], <T>(elt: T) =>
|
||||
elt.reflectedType = $$typeToString!<T>(true, false, true)]
|
||||
}
|
||||
export function $Dreflect<ImplTuple>(tup: ImplTuple) {
|
||||
+[[tup], <T>(elt: T) =>
|
||||
elt.reflectedType = $$typeToString!<T['actualType']>(true, false, true)]
|
||||
}
|
||||
export type RTT = {reflectedType?: string}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import type {configDependency} from '../core/Config.js'
|
||||
import type {Dependencies, Signature} from '../interfaces/type.js'
|
||||
import { $reflecType, $reflecTypes } from '../interfaces/type.js'
|
||||
import type {Dependencies, Signature, RTT, DSignature} from '../interfaces/type.js'
|
||||
import {$reflect, $Dreflect} from '../interfaces/type.js'
|
||||
|
||||
export const add /*: Signature<'add', number>*/ = (a, b) => a + b
|
||||
export const add: Signature<'add', number> & RTT = (a, b) => a + b
|
||||
export const unaryMinus: Signature<'unaryMinus', number> = a => -a
|
||||
export const conj /*: Signature<'conj', number>*/ = a => a
|
||||
export const subtract /*: Signature<'subtract', number>*/ = (a, b) => a - b
|
||||
export const conj: DSignature<'conj', number> = a => a
|
||||
export const subtract = (): Signature<'subtract', number> => (a, b) => a - b
|
||||
export const multiply: Signature<'multiply', number> = (a, b) => a * b
|
||||
export const absquare: Signature<'absquare', number> = a => a * a
|
||||
export const reciprocal: Signature<'reciprocal', number> = a => 1 / a
|
||||
@ -26,5 +26,5 @@ export const sqrt =
|
||||
return dep.complex(0, Math.sqrt(unaryMinus(a)))
|
||||
}
|
||||
}
|
||||
$reflecType!(sqrt)
|
||||
$reflecTypes!([add, conj, subtract])
|
||||
$reflect!([add, sqrt, subtract])
|
||||
$Dreflect!([conj])
|
||||
|
Loading…
Reference in New Issue
Block a user