feat: Add generic operation square
and numeric unequal
(#4)
Co-authored-by: Jos de Jong <wjosdejong@gmail.com> Co-authored-by: Glen Whitney <glen@studioinfinity.org> Reviewed-on: #4
This commit is contained in:
parent
fbec410c42
commit
8c06c8f36e
@ -30,6 +30,19 @@ export interface ComplexReturn<Params> {
|
|||||||
: Params extends BBinary<infer B> ? Complex<B> // binary case
|
: Params extends BBinary<infer B> ? Complex<B> // binary case
|
||||||
: never
|
: 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<R> : never
|
||||||
|
// complex_binary: Params extends BBinary<infer R> ? Complex<R> : 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<R> : 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
|
zero: Params extends [infer Z] // unary
|
||||||
? Z extends Complex<infer T> // of a Complex parameter
|
? Z extends Complex<infer T> // of a Complex parameter
|
||||||
? ImpReturns<'zero', T> extends T ? Z : never // that has its real 0
|
? ImpReturns<'zero', T> extends T ? Z : never // that has its real 0
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
export * from './numbers/all.js'
|
export * from './numbers/all.js'
|
||||||
export * from './Complex/all.js'
|
export * from './Complex/all.js'
|
||||||
|
export * from './generic/all.js'
|
||||||
|
10
src/generic/all.ts
Normal file
10
src/generic/all.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
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<Params>
|
||||||
|
extends ForType<'generic', GenericReturn<Params>> { }
|
||||||
|
}
|
39
src/generic/arithmetic.ts
Normal file
39
src/generic/arithmetic.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import {Dependency, ImpType, ImpReturns} from "../core/Dispatcher";
|
||||||
|
|
||||||
|
declare module "./type" {
|
||||||
|
interface GenericReturn<Params> {
|
||||||
|
// Jos: not sure how to define this or why it is needed
|
||||||
|
// square: Signature<Params, [T], T>
|
||||||
|
// square: ConservativeUnary<Params, T>
|
||||||
|
// square: Params extends [infer R]
|
||||||
|
// ? R extends number ? UnderlyingReal<R> : 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 =
|
||||||
|
<T>(dep: Dependency<'multiply', [T, T]>):
|
||||||
|
ImpType<'square', [T]> =>
|
||||||
|
z => dep.multiply(z, z)
|
3
src/generic/type.ts
Normal file
3
src/generic/type.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export interface GenericReturn<Params> {
|
||||||
|
|
||||||
|
}
|
@ -1,27 +1,34 @@
|
|||||||
import {configDependency} from '../core/Config.js'
|
import {configDependency} from '../core/Config.js'
|
||||||
import {Signature, ImpType} from '../core/Dispatcher.js'
|
import {Signature, ImpType, Dependency} from '../core/Dispatcher.js'
|
||||||
|
|
||||||
const DBL_EPSILON = Number.EPSILON || 2.2204460492503130808472633361816E-16
|
const DBL_EPSILON = Number.EPSILON || 2.2204460492503130808472633361816E-16
|
||||||
|
|
||||||
declare module "./type" {
|
declare module "./type" {
|
||||||
interface NumbersReturn<Params> {
|
interface NumbersReturn<Params> {
|
||||||
equal: Signature<Params, [number, number], boolean>
|
equal: Signature<Params, [number, number], boolean>
|
||||||
|
unequal: Signature<Params, [number, number], boolean>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const equal =
|
export const equal =
|
||||||
(dep: configDependency): ImpType<'equal', [number, number]> =>
|
(dep: configDependency): ImpType<'equal', [number, number]> =>
|
||||||
(x, y) => {
|
(x, y) => {
|
||||||
const eps = dep.config.epsilon
|
const eps = dep.config.epsilon
|
||||||
if (eps === null || eps === undefined) return x === y
|
if (eps === null || eps === undefined) return x === y
|
||||||
if (x === y) return true
|
if (x === y) return true
|
||||||
if (isNaN(x) || isNaN(y)) return false
|
if (isNaN(x) || isNaN(y)) return false
|
||||||
|
|
||||||
if (isFinite(x) && isFinite(y)) {
|
if (isFinite(x) && isFinite(y)) {
|
||||||
const diff = Math.abs(x - y)
|
const diff = Math.abs(x - y)
|
||||||
if (diff < DBL_EPSILON) return true
|
if (diff < DBL_EPSILON) return true
|
||||||
return diff <= Math.max(Math.abs(x), Math.abs(y)) * eps
|
return diff <= Math.max(Math.abs(x), Math.abs(y)) * eps
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
export const unequal = (dep: Dependency<'equal', [number, number]>):
|
||||||
|
ImpType<'unequal', [number, number]> =>
|
||||||
|
(x, y) => {
|
||||||
|
return !dep.equal(x, y)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user