WIP: try to use ts-macros for more implementations

This commit is contained in:
Glen Whitney 2023-09-18 10:14:11 -07:00
parent dc6cf5165d
commit 0e2a1e830a
7 changed files with 30 additions and 111 deletions

View file

@ -2,6 +2,7 @@ import {Complex} from './type.js'
import type {
Dependencies, Signature, Returns, RealType, AliasOf
} from '../interfaces/type.js'
import {$implement} from '../interfaces/type.js'
declare module "../interfaces/type" {
interface Signatures<T> {
@ -73,7 +74,7 @@ export const divide =
// and we have to get it straight which operations we need on each type, and
// in fact, we need `addReal` on both T and Complex<T>, hence the dependency
// with a custom name, not generated via Dependencies<...>
export const sqrt =
$implement!('sqrt',
<T>(dep: Dependencies<'equal' | 'conservativeSqrt' | 'unaryMinus', RealType<T>>
& Dependencies<'zero' | 'complex', T>
& Dependencies<'absquare' | 're' | 'divideReal', Complex<T>>
@ -96,6 +97,6 @@ export const sqrt =
const denomsq = dep.addRR(dep.addRR(myabs, myabs), dep.addRR(r, r))
const denom = dep.conservativeSqrt(denomsq)
return dep.divideReal(num, denom)
}
})
export const conservativeSqrt = sqrt

View file

@ -1,86 +1,7 @@
import type {Dependencies, Signature} from '../interfaces/type.js'
import {$$typeToString, $$ident, $$escape, $$define} from 'ts-macros'
import * as ts from 'typescript'
import {$implement} from '../interfaces/type.js'
export const square =
<T>(dep: Dependencies<'multiply', T>): Signature<'square', T> =>
z => dep.multiply(z, z)
$implement!('square',
<T>(dep: Dependencies<'multiply', T>) => (z:T) => dep.multiply(z, z))
// z => dep.fooBar(z, z) // fails as desired
// z => dep.multiply(z, 'foo') // still fails as desired
// make sure ts-macros is running
function $contains<T>(value: T, ...possible: Array<T>) {
// repetition which goes over all the elements in the "possible" array
return +["||", [possible], (item: T) => value === item];
}
const searchItem = "needle";
console.log("In generic arithmetic")
console.log($contains!(searchItem, "erwin", "tj"));
// Transpiles to: console.log(false);
// OK, record the type of square:
square.reflectedType = //$$typeToString!<typeof square>();
$$typeToString!<
<T>(...args: DeepExpand<Parameters<typeof square<T>>>)
=> DeepExpand<ReturnType<typeof square<T>>>
>()
type ShallowExpand<T> = T extends unknown ? { [K in keyof T]: T[K] } : never;
// Short alias of ShallowExpand for convenience below:
type Deps<T> = T extends unknown ? { [K in keyof T]: T[K] } : never;
type ExpandedParameters<T extends (...args: any) => any> = {[Index in keyof Parameters<T>]: ShallowExpand<Parameters<T>[Index]>}
type ExpandTwice<T extends any[]> = {[Index in keyof T] : ShallowExpand<T[Index]>}
type AsArray<T> = T extends any[] ? T : [];
type DeepExpand<T> =
T extends (...args: any) => any
? (...pars: AsArray<DeepExpand<Parameters<T>>>) => DeepExpand<ReturnType<T>> :
T extends unknown ? { [K in keyof T]: DeepExpand<T[K]> } : never;
type Out<T> = ShallowExpand<Dependencies<'multiply', T>>;
console.log("Deps type is", $$typeToString!<<T>() => Out<T>>())
type OutB = ExpandTwice<Parameters<typeof square>>;
console.log("Or perhaps", $$typeToString!<OutB>())
console.log("Or maybe even", $$typeToString!<
<T>(...args: DeepExpand<Parameters<typeof square<T>>>) => DeepExpand<ReturnType<typeof square<T>>>
>())
// Now try to wrap it up in a macro
function $exportImpl<Impl>(name: string, expr: Impl) {
$$define!(name, expr, false, true); // Final `true` is export
$$ident!(name).reflectedType = $$typeToString!<
// <T>(...args: DeepExpand<Parameters<Impl<T>>>) => DeepExpand<ReturnType<Impl<T>>> // see comment in reflect below.
Impl
>();
}
// works but then not visible at import with current ts-macros.
// Author says he will be enhancing this "soon."
$exportImpl!('squire',
<T>(dep: Dependencies<'multiply', T>): Signature<'square', T> =>
z => dep.multiply(z, z))
function $reflect<Impl>(expr: Impl) {
return $$escape!(() => {
const temp: Impl & {reflectedType?: string} = expr;
temp.reflectedType = $$typeToString!<
// <T>(...args: DeepExpand<Parameters<Impl<T>>>) =>
// DeepExpand<ReturnType<Impl<T>>> // error; can't instantiate
// Impl; even if we constrain it to be the type of a generic function,
// that's still not a generic _type_, ugh.
Impl>();
return temp;
}) as Impl & {reflectedType: string}
}
export const squre = $reflect!(
<T>(dep: Dependencies<'multiply', T>): Signature<'square', T> =>
z => dep.multiply(z, z))
export const sqre = $reflect!(
<T>(dep: Deps<Dependencies<'multiply', T>>): Signature<'square', T> =>
z => dep.multiply(z, z))

View file

@ -21,17 +21,4 @@ console.log('Result is', myabs)
// Check type of the generic square implementation
console.log('Type of square is', Specifications.generic.square.reflectedType)
// Now check the ones that came via macros:
// Auto-generated export is invisible to TypeScript at the moment, author
// says he will fix:
console.log('Type of squire (auto-exported) is',
// not ts-ignore
Specifications.generic.squire.reflectedType)
// Via a macro wrapper around the definition, two ways:
console.log('Type of squre (unexpanded) is',
Specifications.generic.squre.reflectedType)
console.log('Type of sqre (expanded) is',
Specifications.generic.sqre.reflectedType)
console.log('Type of complex square root is', Specifications.Complex.sqrt.reflectedType)

View file

@ -1,3 +1,5 @@
import {$$typeToString, $$ident, $$define} from 'ts-macros'
/*****
* Every typocomath type has some associated types; they need
* to be published in the following interface. The key is the
@ -74,6 +76,13 @@ type SignatureKey<T> = keyof Signatures<T>
export type Signature<Name extends SignatureKey<T>, T> = Signatures<T>[Name]
export type Returns<Name extends SignatureKey<T>, T> = ReturnType<Signatures<T>[Name]>
export type Dependencies<Name extends SignatureKey<T>, T> = {[K in Name]: Signature<K, T>}
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 $implement<Impl>(name: string, expr: Impl) {
$$define!(name, expr, false, true); // Final `true` is export
$$ident!(name).reflectedType = $$typeToString!<Impl>();
}