From d55776655f3bbe64c909bb60c5cfe016f44a5c7d Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Wed, 21 Dec 2022 11:41:25 -0500 Subject: [PATCH] refactor: Convenience type operator for specifying concrete signatures --- src/Complex/type.ts | 5 +++-- src/core/Dispatcher.ts | 12 ++++++++---- src/numbers/arithmetic.ts | 14 +++++++------- src/numbers/type.ts | 4 ++++ 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/Complex/type.ts b/src/Complex/type.ts index a174c40..b0bb5b7 100644 --- a/src/Complex/type.ts +++ b/src/Complex/type.ts @@ -19,9 +19,10 @@ export const Complex_type = { } } -type Binary = [B, B] - export interface ComplexReturn { + // 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 // unary case : Params extends BBinary ? Complex // binary case : never diff --git a/src/core/Dispatcher.ts b/src/core/Dispatcher.ts index 46a8bff..b8d7c60 100644 --- a/src/core/Dispatcher.ts +++ b/src/core/Dispatcher.ts @@ -9,7 +9,7 @@ type TypeName = string type Parameter = TypeName -type Signature = Parameter[] +type InputSignature = Parameter[] type DependenciesType = Record export type typeOfDependency = {typeOf: (x: unknown) => TypeName} @@ -62,7 +62,11 @@ export interface ReturnTypes {} // Helpers for specifying signatures -// A homogenous binary operation (comes up a lot) +// A basic signature with concrete types +export type Signature = + CandidateParams extends ActualParams ? Returns : never + +// A homogenous binary operation (comes up a lot, needs a better name?) // Typical usage: `foo_impl: Params extends BBinary ? 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 export class Dispatcher { installSpecification( name: string, - signature: Signature, + signature: InputSignature, returns: TypeName, - dependencies: Record, + dependencies: Record, behavior: Function // possible todo: constrain this type based // on the signature, return type, and dependencies. Not sure if // that's really possible, though. diff --git a/src/numbers/arithmetic.ts b/src/numbers/arithmetic.ts index bc9b862..9bca0ab 100644 --- a/src/numbers/arithmetic.ts +++ b/src/numbers/arithmetic.ts @@ -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 : never + add: Signature // 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 : never - multiply: Params extends BBinary ? number : never - divide: Params extends BBinary ? number : never + unaryMinus: Signature + subtract: Signature + multiply: Signature + divide: Signature // 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) : never + sqrt: Signature> } } diff --git a/src/numbers/type.ts b/src/numbers/type.ts index a32b791..105ca46 100644 --- a/src/numbers/type.ts +++ b/src/numbers/type.ts @@ -21,6 +21,10 @@ export interface NumbersReturn { zero: Params extends [infer T] ? T extends number ? 0 extends T ? 0 : never : never : never + // Note that in any case the simple + // zero: Signature + // makes complex fail to compile, because it worries that you might be + // making `Complex` where zero would not return the right type. } export const zero: ImpType<'zero', [number]> = a => 0