From cbd171922780b18ad808edb1bdccd76f6718373e Mon Sep 17 00:00:00 2001 From: Jos de Jong Date: Fri, 23 Dec 2022 11:27:39 +0100 Subject: [PATCH] experiment: convert all implementations to plain types --- src/Complex/all.ts | 7 -- src/Complex/arithmetic.ts | 212 ++++++++++++++++++-------------------- src/Complex/predicate.ts | 25 ++--- src/Complex/relational.ts | 18 +--- src/Complex/type.ts | 97 ++++++----------- src/core/Dispatcher.ts | 24 ----- src/generic/all.ts | 7 -- src/generic/arithmetic.ts | 42 +------- src/generic/type.ts | 3 - src/numbers/all.ts | 7 -- src/numbers/arithmetic.ts | 90 +++++----------- src/numbers/predicate.ts | 13 +-- src/numbers/relational.ts | 44 ++++---- src/numbers/type.ts | 44 +------- 14 files changed, 198 insertions(+), 435 deletions(-) delete mode 100644 src/generic/type.ts diff --git a/src/Complex/all.ts b/src/Complex/all.ts index f5369ec..b0ec237 100644 --- a/src/Complex/all.ts +++ b/src/Complex/all.ts @@ -1,10 +1,3 @@ -import {ForType} from '../core/Dispatcher.js' -import {ComplexReturn} from './type.js' import * as Complex from './native.js' export {Complex} - -declare module "../core/Dispatcher" { - interface ReturnTypes - extends ForType<'Complex', ComplexReturn> {} -} diff --git a/src/Complex/arithmetic.ts b/src/Complex/arithmetic.ts index 8fc32fb..941a654 100644 --- a/src/Complex/arithmetic.ts +++ b/src/Complex/arithmetic.ts @@ -1,139 +1,127 @@ -import {Complex, UnderlyingReal, complex_binary} from './type.js' -import { - BBinary, Dependency, ConservativeUnary, ConservativeBinary, ImpType -} from '../core/Dispatcher.js' - -declare module "./type" { - interface ComplexReturn { - add: ConservativeBinary> - addReal: Params extends [infer Z, infer R] - ? [R] extends [UnderlyingReal] ? Z : never - : never - unaryMinus: ConservativeUnary> - conj: ConservativeUnary> - subtract: ConservativeBinary> - multiply: ConservativeBinary> - absquare: Params extends [infer Z] - ? Z extends Complex ? UnderlyingReal : never - : never - reciprocal: ConservativeUnary> - divide: ConservativeBinary> - divideByReal: Params extends [infer Z, infer R] - ? [R] extends [UnderlyingReal] ? Z : never - : never - // square root that remains the same type - conservativeSqrt: ConservativeUnary> - // Same as conservativeSqrt for complex numbers: - sqrt: ConservativeUnary> - - // complex square root of the real type of a complex: - complexSqrt: Params extends [infer T] ? Complex : never - } -} +import { Complex, complex_binary } from './type.js' export const add = - (dep: Dependency<'add', [T,T]>): - ImpType<'add', [Complex, Complex]> => - (w, z) => complex_binary(dep.add(w.re, z.re), dep.add(w.im, z.im)) + (dep: { + add: (a: T, b: T) => T + }) => + (w: Complex, z: Complex): Complex => + complex_binary(dep.add(w.re, z.re), dep.add(w.im, z.im)) export const addReal = - (dep: Dependency<'addReal', [T, UnderlyingReal]>): - ImpType<'addReal', [Complex, UnderlyingReal]> => - (z, r) => complex_binary(dep.addReal(z.re, r), z.im) + (dep: { + addReal: (a: T, b: T) => T + }) => + (z: Complex, r: T): Complex => + complex_binary(dep.addReal(z.re, r), z.im) export const unaryMinus = - (dep: Dependency<'unaryMinus', [T]>): - ImpType<'unaryMinus', [Complex]> => - z => complex_binary(dep.unaryMinus(z.re), dep.unaryMinus(z.im)) + (dep: { + unaryMinus: (z: T) => T + }) => + (z: Complex): Complex => + complex_binary(dep.unaryMinus(z.re), dep.unaryMinus(z.im)) export const conj = - (dep: Dependency<'unaryMinus'|'conj', [T]>): - ImpType<'conj', [Complex]> => - z => complex_binary(dep.conj(z.re), dep.unaryMinus(z.im)) + (dep: { + unaryMinus: (z: T) => T, + conj: (z: T) => T + }) => + (z: Complex): Complex => + complex_binary(dep.conj(z.re), dep.unaryMinus(z.im)) export const subtract = - (dep: Dependency<'subtract', [T,T]>): - ImpType<'subtract', [Complex, Complex]> => - (w, z) => complex_binary(dep.subtract(w.re, z.re), dep.subtract(w.im, z.im)) + (dep: { + subtract: (a: T, b: T) => T + }) => + (w: Complex, z: Complex): Complex => + complex_binary(dep.subtract(w.re, z.re), dep.subtract(w.im, z.im)) export const multiply = - (dep: Dependency<'add', [T,T]> - & Dependency<'subtract', [T,T]> - & Dependency<'multiply', [T,T]> - & Dependency<'conj', [T]>): - ImpType<'multiply', [Complex, Complex]> => - (w, z) => { - const mult = dep.multiply - const realpart = dep.subtract( - mult( w.re, z.re), mult(dep.conj(w.im), z.im)) - const imagpart = dep.add( - mult(dep.conj(w.re), z.im), mult( w.im, z.re)) - return complex_binary(realpart, imagpart) - } + (dep: { + add: (a: T, b: T) => T, + subtract: (a: T, b: T) => T, + multiply: (a: T, b: T) => T, + conj: (z: T) => T + }) => + (w: Complex, z: Complex): Complex => { + const mult = dep.multiply + const realpart = dep.subtract(mult(w.re, z.re), mult(dep.conj(w.im), z.im)) + const imagpart = dep.add(mult(dep.conj(w.re), z.im), mult(w.im, z.re)) + return complex_binary(realpart, imagpart) + } export const absquare = - (dep: Dependency<'absquare', [T]> - & Dependency<'add', BBinary>>): - ImpType<'absquare', [Complex]> => - z => dep.add(dep.absquare(z.re), dep.absquare(z.im)) + (dep: { + add: (a: T, b: T) => T, + absquare: (z: T) => T + }) => + (z: Complex): T => dep.add(dep.absquare(z.re), dep.absquare(z.im)) export const divideByReal = - (dep: Dependency<'divideByReal', [T, UnderlyingReal]>): - ImpType<'divideByReal', [Complex, UnderlyingReal]> => - (z, r) => complex_binary( - dep.divideByReal(z.re, r), dep.divideByReal(z.im, r)) + (dep: { + divideByReal: (a: T, b: T) => T + }) => + (z: Complex, r: T) => + complex_binary(dep.divideByReal(z.re, r), dep.divideByReal(z.im, r)) export const reciprocal = - (dep: Dependency<'conj', [Complex]> - & Dependency<'absquare', [Complex]> - & Dependency<'divideByReal', [Complex, UnderlyingReal]>): - ImpType<'reciprocal', [Complex]> => - z => dep.divideByReal(dep.conj(z), dep.absquare(z)) + (dep: { + conj: (z: Complex) => Complex, + absquare: (z: Complex) => T, + divideByReal: (a: Complex, b: T) => Complex, + zero: (z: T) => T, + }) => + (z: Complex): Complex => dep.divideByReal(dep.conj(z), dep.absquare(z)) export const divide = - (dep: Dependency<'multiply', [Complex, Complex]> - & Dependency<'reciprocal', [Complex]>): - ImpType<'divide', [Complex, Complex]> => - (w, z) => dep.multiply(w, dep.reciprocal(z)) + (dep: { + multiply: (a: Complex, b: Complex) => Complex, + reciprocal: (z: Complex) => Complex, + }) => + (w: Complex, z: Complex) => dep.multiply(w, dep.reciprocal(z)) export const complexSqrt = - (dep: Dependency<'conservativeSqrt', [T]> - & Dependency<'isSquare', [T]> - & Dependency<'complex', [T]> - & Dependency<'unaryMinus', [T]> - & Dependency<'zero', [T]> - & Dependency<'nan', [Complex]>): ImpType<'complexSqrt', [T]> => - r => { - if (dep.isSquare(r)) return dep.complex(dep.conservativeSqrt(r)) - const negative = dep.unaryMinus(r) - if (dep.isSquare(negative)) { - return complex_binary( - dep.zero(r), dep.conservativeSqrt(negative)) + (dep: { + conservativeSqrt: (a: T) => T, + isSquare: (a: T) => boolean, + complex: (a: T) => Complex, + unaryMinus: (a: T) => T, + zero: (a: T) => T, + nan: (a: Complex) => Complex + }) => + (r: T): Complex => { + if (dep.isSquare(r)) return dep.complex(dep.conservativeSqrt(r)) + const negative = dep.unaryMinus(r) + if (dep.isSquare(negative)) { + return complex_binary( + dep.zero(r), dep.conservativeSqrt(negative)) + } + // neither the real number or its negative is a square; could happen + // for example with bigint. So there is no square root. So we have to + // return the NaN of the type. + return dep.nan(dep.complex(r)) } - // neither the real number or its negative is a square; could happen - // for example with bigint. So there is no square root. So we have to - // return the NaN of the type. - return dep.nan(dep.complex(r)) - } export const sqrt = - (dep: Dependency<'isReal', [Complex]> - & Dependency<'complexSqrt', [T]> - & Dependency<'absquare', [Complex]> - & Dependency<'conservativeSqrt', [UnderlyingReal]> - & Dependency<'addReal', [Complex,UnderlyingReal]> - & Dependency<'re', [Complex]> - & Dependency<'add', [UnderlyingReal,UnderlyingReal]> - & Dependency<'divideByReal', [Complex,UnderlyingReal]> - ): ImpType<'sqrt', [Complex]> => - z => { - if (dep.isReal(z)) return dep.complexSqrt(z.re) - const myabs = dep.conservativeSqrt(dep.absquare(z)) - const num = dep.addReal(z, myabs) - const r = dep.re(z) - const denomsq = dep.add(dep.add(myabs, myabs), dep.add(r, r)) - const denom = dep.conservativeSqrt(denomsq) - return dep.divideByReal(num, denom) - } + (dep: { + isReal: (z: Complex) => boolean, + complexSqrt: (a: T) => Complex, + conservativeSqrt: (a: T) => T, + absquare: (a: Complex) => T, + addReal: (a: Complex, b: T) => Complex, + divideByReal: (a: Complex, b: T) => Complex, + add: (a: T, b: T) => T, + re: (a: Complex) => T, + + }) => + (z: Complex) => { + if (dep.isReal(z)) return dep.complexSqrt(z.re) + const myabs = dep.conservativeSqrt(dep.absquare(z)) + const num = dep.addReal(z, myabs) + const r = dep.re(z) + const denomsq = dep.add(dep.add(myabs, myabs), dep.add(r, r)) + const denom = dep.conservativeSqrt(denomsq) + return dep.divideByReal(num, denom) + } export const conservativeSqrt = sqrt diff --git a/src/Complex/predicate.ts b/src/Complex/predicate.ts index eafc5ad..47365fb 100644 --- a/src/Complex/predicate.ts +++ b/src/Complex/predicate.ts @@ -1,19 +1,12 @@ -import {Complex} from './type.js' -import {Signature, Dependency, ImpType} from '../core/Dispatcher.js' - -declare module "./type" { - interface ComplexReturn { - isReal: Signature], boolean> - isSquare: Signature], boolean> - } -} +import { Complex } from './type.js' export const isReal = - (dep: Dependency<'equal', [T,T]> - & Dependency<'add', [T,T]> - & Dependency<'isReal', [T]> - ): ImpType<'isReal', [Complex]> => - z => dep.isReal(z.re) && dep.equal(z.re, dep.add(z.re, z.im)) + (dep: { + equal: (a: T, b: T) => boolean, + add: (a: T, b: T) => T, + isReal: (z: T) => boolean + }) => + (z: Complex) => dep.isReal(z.re) && dep.equal(z.re, dep.add(z.re, z.im)) -export const isSquare: ImpType<'isSquare', [Complex]> = - z => true // FIXME: not correct for Complex once we get there +export const isSquare = + (z: Complex) => true // FIXME: not correct for Complex once we get there diff --git a/src/Complex/relational.ts b/src/Complex/relational.ts index 2a57dc4..2621972 100644 --- a/src/Complex/relational.ts +++ b/src/Complex/relational.ts @@ -1,15 +1,7 @@ -import {Complex} from './type.js' -import {BBinary, ImpType, Dependency} from '../core/Dispatcher.js' - -declare module "./type" { - interface ComplexReturn { - equal: Params extends BBinary - ? B extends Complex ? boolean : never - : never - } -} +import { Complex } from './type.js' export const equal = - (dep: Dependency<'equal', [T,T]>): - ImpType<'equal', [Complex, Complex]> => - (w, z) => dep.equal(w.re, z.re) && dep.equal(w.im, z.im) + (dep: { + equal: (a: T, b: T) => boolean + }) => + (w: Complex, z: Complex): boolean => dep.equal(w.re, z.re) && dep.equal(w.im, z.im) diff --git a/src/Complex/type.ts b/src/Complex/type.ts index 36c040a..d0845c8 100644 --- a/src/Complex/type.ts +++ b/src/Complex/type.ts @@ -1,87 +1,54 @@ import { - joinTypes, typeOfDependency, Dependency, BBinary, ImpType, ImpReturns + joinTypes, typeOfDependency, Dependency, } from '../core/Dispatcher.js' -export type Complex = {re: T; im: T;} - -export type UnderlyingReal = - T extends Complex ? UnderlyingReal : T +export type Complex = { re: T; im: T; } export const Complex_type = { - test: (dep: {testT: (z: unknown) => z is T}) => + test: (dep: { testT: (z: unknown) => z is T }) => (z: unknown): z is Complex => - typeof z === 'object' && 're' in z && 'im' in z - && dep.testT(z.re) && dep.testT(z.im), + typeof z === 'object' && 're' in z && 'im' in z + && dep.testT(z.re) && dep.testT(z.im), infer: (dep: typeOfDependency) => (z: Complex) => joinTypes(dep.typeOf(z.re), dep.typeOf(z.im)), from: { T: (dep: Dependency<'zero', [T]>) => (t: T) => - ({re: t, im: dep.zero(t)}), - Complex: (dep: {convert: (from: U) => T}) => - (z: Complex) => ({re: dep.convert(z.re), im: dep.convert(z.im)}) + ({ re: t, im: dep.zero(t) }), + Complex: (dep: { convert: (from: U) => T }) => + (z: Complex) => ({ re: dep.convert(z.re), im: dep.convert(z.im) }) } } -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 - - // alternatively if it seems better; each definition is simpler, but at - // the cost of having two keys here: - // complex_unary: Params extends [infer R] ? Complex : never - // complex_binary: Params extends BBinary ? Complex : never - - // There is actually a subtlety here that complex_unary really only works - // on real types that include their own zero value, so it should really be - // complex_unary: Params extends [infer R] - // ? ImpReturns<'zero', [R]> extends R ? Complex : never - // : never - // and that might actually simplify some of the typings of other operations, - // but we'll leave such fine tuning til later, if we adopt this scheme - - zero: Params extends [infer Z] // unary - ? Z extends Complex // of a Complex parameter - ? ImpReturns<'zero', T> extends T ? Z : never // that has its real 0 - : never - : never - one: Params extends [infer Z] // unary - ? Z extends Complex // of a Complex parameter - ? ImpReturns<'one'|'zero', T> extends T ? Z : never // has real 1, 0 - : never - : never - nan: Params extends [infer Z] // unary - ? Z extends Complex // of a Complex parameter - ? ImpReturns<'nan', T> extends T ? Z : never // has real NaN - : never - : never - re: Params extends [infer Z] - ? Z extends Complex ? UnderlyingReal : never - : never -} - export const complex_unary = - (dep: Dependency<'zero', [T]>): ImpType<'complex', [T]> => - t => ({re: t, im: dep.zero(t)}) -export const complex_binary = (t: T, u: T): ImpReturns<'complex', [T,T]> => - ({re: t, im: u}) + (dep: { + zero: (z: T) => Complex + }) => + (t: T) => ({ re: t, im: dep.zero(t) }) + +export const complex_binary = + (t: T, u: T): Complex => ({ re: t, im: u }) export const zero = - (dep: Dependency<'zero', [T]>): ImpType<'zero', [Complex]> => - z => complex_binary(dep.zero(z.re), dep.zero(z.im)) + (dep: { + zero: (z: T) => T + }) => + (z: Complex): Complex => complex_binary(dep.zero(z.re), dep.zero(z.im)) export const one = - (dep: Dependency<'zero' | 'one', [T]>): ImpType<'one', [Complex]> => - z => // Must provide parameter T, else TS narrows to return type of dep.one - complex_binary(dep.one(z.re), dep.zero(z.im)) + (dep: { + zero: (z: T) => T, + one: (z: T) => T + }) => + (z: Complex): Complex => complex_binary(dep.one(z.re), dep.zero(z.im)) export const nan = - (dep: Dependency<'nan', [T]>): ImpType<'nan', [Complex]> => - z => complex_binary(dep.nan(z.re), dep.nan(z.im)) + (dep: { + nan: (z: T) => T + }) => + (z: Complex): Complex => complex_binary(dep.nan(z.re), dep.nan(z.im)) export const re = - (dep: Dependency<'re', [T]>): ImpType<'re', [Complex]> => - z => dep.re(z.re) + (dep: { + re: (z: T) => T + }) => + (z: Complex): T => dep.re(z.re) diff --git a/src/core/Dispatcher.ts b/src/core/Dispatcher.ts index aa4c6a9..9b005d9 100644 --- a/src/core/Dispatcher.ts +++ b/src/core/Dispatcher.ts @@ -66,30 +66,6 @@ export interface ReturnTypes {} export type Signature = CandidateParams extends ActualParams ? Returns : never -// A homogeneous binary parameter tuple (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. -export type BBinary = [B, B] - -// A unary signature that preserves the type of its argument, which must -// extend the given Bound: -export type ConservativeUnary = - CandidateParams extends [infer T] ? T extends Bound ? T : never : never - -// A homogeneous binary signature that preserves the common type of its -// arguments, which must extend the given Bound: -export type ConservativeBinary = - CandidateParams extends BBinary - ? B extends Bound ? B : never - : never - -// Helper for collecting return types -// (Really just adds the literal string Suffix onto the keys of interface IFace) -export type ForType = keyof IFace extends string - ? {[K in keyof IFace as `${K}_${Suffix}`]: IFace[K]} - : never - //dummy implementation for now export function joinTypes(a: TypeName, b: TypeName) { if (a === b) return a diff --git a/src/generic/all.ts b/src/generic/all.ts index 1a008ac..1b1b8a4 100644 --- a/src/generic/all.ts +++ b/src/generic/all.ts @@ -1,10 +1,3 @@ -import { ForType } from '../core/Dispatcher.js' -import { GenericReturn } from './type.js' import * as generic from './arithmetic.js' export { generic } - -declare module "../core/Dispatcher" { - interface ReturnTypes - extends ForType<'generic', GenericReturn> { } -} diff --git a/src/generic/arithmetic.ts b/src/generic/arithmetic.ts index 46d6922..99a7aab 100644 --- a/src/generic/arithmetic.ts +++ b/src/generic/arithmetic.ts @@ -1,39 +1,5 @@ -import {Dependency, ImpType, ImpReturns} from "../core/Dispatcher"; - -declare module "./type" { - interface GenericReturn { - // Jos: not sure how to define this or why it is needed - // square: Signature - // square: ConservativeUnary - // square: Params extends [infer R] - // ? R extends number ? UnderlyingReal : never - // : never - - // The type of `square` in this interface, instantiated with the type - // Params of a parameter list, needs to be the return type of the - // operation `square` on those parameters. In other words, `square` gives - // a type transformer from the tuple type of its parameters to its return - // type. - // That's how Dispatcher knows what the return type will be in - // `Dependency<'square', [bigint]>`, for example: it instantiates - // GenericReturn with Params equal to [bigint] and then grabs the - // type of the `square` property. Hence we write: - - square: Params extends [infer T] // square only takes 1 arbitrary parameter - ? ImpReturns<'multiply', [T, T]> // and returns whatever multiply does - : never; // otherwise if not a single argument, this implementation - // doesn't handle it - - // If square had more than one implementation in this collection, we could - // either add more conditional clauses to the above type transformer - // as I did in Complex/type.ts for `complex`, or we could have two - // different keys that both start with `square_` and Dispatcher will - // check both (as I have now done in comments in Complex/type.ts and - // verified that also works). - } -} - export const square = - (dep: Dependency<'multiply', [T, T]>): - ImpType<'square', [T]> => - z => dep.multiply(z, z) + (dep: { + multiply: (x: T, y: T) => T + }) => + (z: T): T => dep.multiply(z, z) diff --git a/src/generic/type.ts b/src/generic/type.ts deleted file mode 100644 index 8589417..0000000 --- a/src/generic/type.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface GenericReturn { - -} \ No newline at end of file diff --git a/src/numbers/all.ts b/src/numbers/all.ts index b034f25..deb4a8e 100644 --- a/src/numbers/all.ts +++ b/src/numbers/all.ts @@ -1,10 +1,3 @@ -import {ForType} from '../core/Dispatcher.js' -import {NumbersReturn} from './type.js' import * as numbers from './native.js' export {numbers} - -declare module "../core/Dispatcher" { - interface ReturnTypes - extends ForType<'numbers', NumbersReturn> {} -} diff --git a/src/numbers/arithmetic.ts b/src/numbers/arithmetic.ts index b02b09f..499a942 100644 --- a/src/numbers/arithmetic.ts +++ b/src/numbers/arithmetic.ts @@ -1,72 +1,28 @@ -import {configDependency} from '../core/Config.js' -import { - Signature, ConservativeBinary, ConservativeUnary, Dependency, ImpType -} from '../core/Dispatcher.js' -import type {Complex, UnderlyingReal} from '../Complex/type.js' +import { Config } from '../core/Config.js' +import type { Complex } from '../Complex/type.js' -declare module "./type" { - interface NumbersReturn { - // 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: Signature - - // Whereas this one preserves information, but lies - // because it claims all subtypes of number are closed under addition, - // which is not true for `1 | 2 | 3`, for example. But because in - // generics that use add we often need to assign the result of add - // to something of the exact generic type, generics using add won't - // compile unless we lie in this way and assert that add returns - // the subtype. - add: ConservativeBinary - // Not sure how this will need to go when we introduce NumInt. - - addReal: Params extends [infer R, infer S] - ? R extends number ? S extends R ? R : never : never - : never - unaryMinus: ConservativeUnary - conj: ConservativeUnary - subtract: ConservativeBinary - multiply: ConservativeBinary - absquare: Params extends [infer R] - ? R extends number ? UnderlyingReal : never - : never - reciprocal: ConservativeUnary - divide: ConservativeBinary - divideByReal: Params extends [infer R, infer S] - ? R extends number ? S extends R ? R : never : never - : never - // best square root that remains the same type - conservativeSqrt: ConservativeUnary - // 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: Signature> - } -} - -export const add: ImpType<'add', [number, number]> = (a, b) => a + b +export const add = (a: number, b: number): number => a + b export const addReal = add -export const unaryMinus: ImpType<'unaryMinus', [number]> = a => -a -export const conj: ImpType<'conj', [number]> = a => a -export const subtract: ImpType<'subtract', [number, number]> = (a, b) => a - b -export const multiply: ImpType<'multiply', [number, number]> = (a, b) => a * b -export const absquare: ImpType<'absquare', [number]> = a => a*a -export const reciprocal: ImpType<'reciprocal', [number]> = a => 1/a -export const divide: ImpType<'divide', [number, number]> = (a, b) => a / b -export const divideByReal: ImpType<'divideByReal', [number, number]> = divide +export const unaryMinus = (a: number): number => -a +export const conj = (a: number): number => a +export const subtract = (a: number, b: number): number => a - b +export const multiply = (a: number, b: number): number => a * b +export const absquare = (a: number): number => a * a +export const reciprocal = (a: number): number => 1 / a +export const divide = (a: number, b: number): number => a / b +export const divideByReal = divide -export const conservativeSqrt: ImpType<'conservativeSqrt', [number]> = - a => isNaN(a) ? NaN : Math.sqrt(a) +export const conservativeSqrt = (a: number): number => isNaN(a) ? NaN : Math.sqrt(a) export const sqrt = - (dep: configDependency - & Dependency<'complex', [number, number]>): ImpType<'sqrt', [number]> => { - if (dep.config.predictable || !dep.complex) return conservativeSqrt - return a => { - if (isNaN(a)) return NaN - if (a >= 0) return Math.sqrt(a) - return dep.complex(0, Math.sqrt(unaryMinus(a))) - } - } + (dep: { + config: Config, + complex: (re: number, im: number) => Complex + }): (a: number) => number | Complex => { + if (dep.config.predictable || !dep.complex) return conservativeSqrt + return a => { + if (isNaN(a)) return NaN + if (a >= 0) return Math.sqrt(a) + return dep.complex(0, Math.sqrt(unaryMinus(a))) + } + } diff --git a/src/numbers/predicate.ts b/src/numbers/predicate.ts index b8cc4c5..483b103 100644 --- a/src/numbers/predicate.ts +++ b/src/numbers/predicate.ts @@ -1,11 +1,2 @@ -import {Signature, ImpType} from '../core/Dispatcher.js' - -declare module "./type" { - interface NumbersReturn { - isReal: Signature - isSquare: Signature - } -} - -export const isReal: ImpType<'isReal', [number]> = a => true -export const isSquare: ImpType<'isSquare', [number]> = a => a >= 0 +export const isReal = (a: number) : boolean => true +export const isSquare = (a: number) : boolean => a >= 0 diff --git a/src/numbers/relational.ts b/src/numbers/relational.ts index 51d7e07..dac949a 100644 --- a/src/numbers/relational.ts +++ b/src/numbers/relational.ts @@ -1,34 +1,26 @@ -import {configDependency} from '../core/Config.js' -import {Signature, ImpType, Dependency} from '../core/Dispatcher.js' +import { Config } from '../core/Config.js' const DBL_EPSILON = Number.EPSILON || 2.2204460492503130808472633361816E-16 -declare module "./type" { - interface NumbersReturn { - equal: Signature - unequal: Signature - } -} - export const equal = - (dep: configDependency): ImpType<'equal', [number, number]> => - (x, y) => { - const eps = dep.config.epsilon - if (eps === null || eps === undefined) return x === y - if (x === y) return true - if (isNaN(x) || isNaN(y)) return false + (dep: { + config: Config + }) => (x: number, y: number): boolean => { + const eps = dep.config.epsilon + if (eps === null || eps === undefined) return x === y + if (x === y) return true + if (isNaN(x) || isNaN(y)) return false - if (isFinite(x) && isFinite(y)) { - const diff = Math.abs(x - y) - if (diff < DBL_EPSILON) return true - return diff <= Math.max(Math.abs(x), Math.abs(y)) * eps - } - - return false + if (isFinite(x) && isFinite(y)) { + const diff = Math.abs(x - y) + if (diff < DBL_EPSILON) return true + return diff <= Math.max(Math.abs(x), Math.abs(y)) * eps } -export const unequal = (dep: Dependency<'equal', [number, number]>): - ImpType<'unequal', [number, number]> => - (x, y) => { - return !dep.equal(x, y) + return false } + +export const unequal = (dep: { + equal: (x: number, y: number) => boolean +}) => + (x: number, y: number): boolean => !dep.equal(x, y) diff --git a/src/numbers/type.ts b/src/numbers/type.ts index 46971fc..46fbf6f 100644 --- a/src/numbers/type.ts +++ b/src/numbers/type.ts @@ -1,44 +1,10 @@ -import {ImpType} from '../core/Dispatcher.js' -import type {UnderlyingReal} from '../Complex/type.js' - export const number_type = { before: ['Complex'], test: (n: unknown): n is number => typeof n === 'number', - from: {string: s => +s} + from: { string: (s: string) => +s } } - -export interface NumbersReturn { - // The following description of the return type of `zero` on a single - // number argument has ended up unfortunately rather complicated. However, - // it illustrates the typing is really working: Suppose we have a - // `type Small = 1 | 2 | 3`. Then Small indeed extends number, but we - // can't use the operation `zero(s: Small)` because zero is supposed to - // return something of the same type as its argument, but there is no - // zero in Small. Anyhow, in plain language the below says that given - // one parameter of a subtype of number, as long as that subtype includes 0, - // the zero operation returns a member of the type `0` (so we know even - // at compile time that its value will be 0). - 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. - - one: Params extends [infer T] - ? T extends number ? 1 extends T ? 1 : never : never - : never - nan: Params extends [infer T] - ? T extends number ? typeof NaN extends T ? typeof NaN : never : never - : never - re: Params extends [infer T] - ? T extends number ? UnderlyingReal : never - : never -} - -export const zero: ImpType<'zero', [number]> = a => 0 -export const one: ImpType<'one', [number]> = a => 1 -export const nan: ImpType<'nan', [number]> = a => NaN -export const re: ImpType<'re', [number]> = a => a +export const zero = (a: number): number => 0 +export const one = (a: number): number => 1 +export const nan = (a: number): number => NaN +export const re = (a: number): number => a