refactor: Convenience type operator for specifying concrete signatures

This commit is contained in:
Glen Whitney 2022-12-21 11:41:25 -05:00
parent 1eb73be2fa
commit d55776655f
4 changed files with 22 additions and 13 deletions

View File

@ -19,9 +19,10 @@ export const Complex_type = {
}
}
type Binary<B> = [B, B]
export interface ComplexReturn<Params> {
// Sadly, I can't think of a way to make some nice abbreviation operators
// for these generic type specifications because TypeScript generics
// can't take and use generic parameters, only fully instantiated types.
complex: Params extends [infer U] ? Complex<U> // unary case
: Params extends BBinary<infer B> ? Complex<B> // binary case
: never

View File

@ -9,7 +9,7 @@
type TypeName = string
type Parameter = TypeName
type Signature = Parameter[]
type InputSignature = Parameter[]
type DependenciesType = Record<string, Function>
export type typeOfDependency = {typeOf: (x: unknown) => TypeName}
@ -62,7 +62,11 @@ export interface ReturnTypes<Params> {}
// Helpers for specifying signatures
// A homogenous binary operation (comes up a lot)
// A basic signature with concrete types
export type Signature<CandidateParams, ActualParams, Returns> =
CandidateParams extends ActualParams ? Returns : never
// A homogenous binary operation (comes up a lot, needs a better name?)
// Typical usage: `foo_impl: Params extends BBinary<infer B> ? B : never`
// says that this implementation takes two arguments, both of type B, and
// returns the same type.
@ -118,9 +122,9 @@ type SpecificationsGroup = Record<string, SpecObject>
export class Dispatcher {
installSpecification(
name: string,
signature: Signature,
signature: InputSignature,
returns: TypeName,
dependencies: Record<string, Signature>,
dependencies: Record<string, InputSignature>,
behavior: Function // possible todo: constrain this type based
// on the signature, return type, and dependencies. Not sure if
// that's really possible, though.

View File

@ -1,5 +1,5 @@
import {configDependency} from '../core/Config.js'
import {BBinary, Dependency, ImpType} from '../core/Dispatcher.js'
import {Signature, Dependency, ImpType} from '../core/Dispatcher.js'
import type {Complex} from '../Complex/type.js'
declare module "./type" {
@ -7,7 +7,7 @@ declare module "./type" {
// This description loses information: some subtypes like NumInt or
// Positive are closed under addition, but this says that the result
// of add is just a number, not still of the reduced type
add: Params extends BBinary<number> ? number : never
add: Signature<Params, [number, number], number>
// Whereas this one would preserve information, but would lie
// because it claims all subtypes of number are closed under addition,
// which is not true for `1 | 2 | 3`, for example.
@ -16,15 +16,15 @@ declare module "./type" {
// : never
//
// Not sure how this will need to go when we introduce NumInt.
unaryMinus: Params extends [number] ? number : never
subtract: Params extends BBinary<number> ? number : never
multiply: Params extends BBinary<number> ? number : never
divide: Params extends BBinary<number> ? number : never
unaryMinus: Signature<Params, [number], number>
subtract: Signature<Params, [number, number], number>
multiply: Signature<Params, [number, number], number>
divide: Signature<Params, [number, number], number>
// Best we can do for sqrt at compile time, since actual return
// type depends on config. Not sure how this will play out
// when we make a number-only bundle, but at least the import type
// above for Complex<> does not lead to any emitted JavaScript.
sqrt: Params extends [number] ? (number | Complex<number>) : never
sqrt: Signature<Params, [number], number | Complex<number>>
}
}

View File

@ -21,6 +21,10 @@ export interface NumbersReturn<Params> {
zero: Params extends [infer T]
? T extends number ? 0 extends T ? 0 : never : never
: never
// Note that in any case the simple
// zero: Signature<Params, [number], 0>
// makes complex fail to compile, because it worries that you might be
// making `Complex<Small>` where zero would not return the right type.
}
export const zero: ImpType<'zero', [number]> = a => 0