feat: Return type annotations #53
@ -3,7 +3,7 @@ export * from './Types/bigint.mjs'
|
|||||||
|
|
||||||
export const divide = {
|
export const divide = {
|
||||||
'bigint,bigint': ({config, 'quotient(bigint,bigint)': quot}) => {
|
'bigint,bigint': ({config, 'quotient(bigint,bigint)': quot}) => {
|
||||||
if (config.predictable) return quot
|
if (config.predictable) return Returns('bigint', (n,d) => quot(n,d))
|
||||||
return Returns('bigint|undefined', (n, d) => {
|
return Returns('bigint|undefined', (n, d) => {
|
||||||
const q = n/d
|
const q = n/d
|
||||||
if (q * d == n) return q
|
if (q * d == n) return q
|
||||||
|
@ -6,7 +6,7 @@ const Complex = new PocomathInstance('Complex')
|
|||||||
Complex.installType('Complex', {
|
Complex.installType('Complex', {
|
||||||
test: z => z && typeof z === 'object' && 're' in z && 'im' in z
|
test: z => z && typeof z === 'object' && 're' in z && 'im' in z
|
||||||
})
|
})
|
||||||
// Now the template type: Complex numbers are actually always homeogeneous
|
// Now the template type: Complex numbers are actually always homogeneous
|
||||||
// in their component types.
|
// in their component types.
|
||||||
Complex.installType('Complex<T>', {
|
Complex.installType('Complex<T>', {
|
||||||
infer: ({typeOf, joinTypes}) => z => joinTypes([typeOf(z.re), typeOf(z.im)]),
|
infer: ({typeOf, joinTypes}) => z => joinTypes([typeOf(z.re), typeOf(z.im)]),
|
||||||
|
@ -1,10 +1,25 @@
|
|||||||
|
import {Returns, returnTypeOf} from '../core/Returns.mjs'
|
||||||
export * from './Types/Complex.mjs'
|
export * from './Types/Complex.mjs'
|
||||||
|
|
||||||
export const abs = {
|
export const abs = {
|
||||||
'Complex<T>': ({
|
'Complex<T>': ({
|
||||||
sqrt, // Calculation of the type needed in the square root (the
|
sqrt, // Unfortunately no notation yet for the needed signature
|
||||||
// underlying numeric type of T, whatever T is, is beyond Pocomath's
|
'absquare(T)': baseabsq,
|
||||||
// (current) template abilities, so punt and just do full resolution
|
|
||||||
'absquare(Complex<T>)': absq
|
'absquare(Complex<T>)': absq
|
||||||
}) => z => sqrt(absq(z))
|
}) => {
|
||||||
|
const pm = sqrt.fromInstance
|
||||||
|
if (typeof pm === 'undefined') {
|
||||||
|
// Just checking for the dependencies, return value is irrelevant
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
const midType = returnTypeOf(baseabsq)
|
||||||
|
const sqrtImp = pm.resolve('sqrt', midType, sqrt)
|
||||||
|
let retType = returnTypeOf(sqrtImp)
|
||||||
|
if (retType.includes('|')) {
|
||||||
|
// This is a bit of a hack, as it relies on all implementations of
|
||||||
|
// sqrt returning the "typical" return type as the first option
|
||||||
|
retType = retType.split('|',1)[0]
|
||||||
|
}
|
||||||
|
return Returns(retType, z => sqrtImp(absq(z)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,31 @@
|
|||||||
|
import {Returns, returnTypeOf} from '../core/Returns.mjs'
|
||||||
export * from './Types/Complex.mjs'
|
export * from './Types/Complex.mjs'
|
||||||
|
|
||||||
export const absquare = {
|
export const absquare = {
|
||||||
'Complex<T>': ({
|
'Complex<T>': ({
|
||||||
add, // Calculation of exact type needed in add (underlying numeric of T)
|
add, // no easy way to write the needed signature; if T is number
|
||||||
// is (currently) too involved for Pocomath
|
// it is number,number; but if T is Complex<bigint>, it is just
|
||||||
|
// bigint,bigint. So unfortunately we depend on all of add, and
|
||||||
|
// we extract the needed implementation below.
|
||||||
'self(T)': absq
|
'self(T)': absq
|
||||||
}) => z => add(absq(z.re), absq(z.im))
|
}) => {
|
||||||
|
const pm = add.fromInstance
|
||||||
|
if (typeof pm === 'undefined') {
|
||||||
|
// Just checking the dependencies, return value irrelevant
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
const midType = returnTypeOf(absq)
|
||||||
|
const addImp = pm.resolve('add', `${midType},${midType}`, add)
|
||||||
|
return Returns(
|
||||||
|
returnTypeOf(addImp), z => addImp(absq(z.re), absq(z.im)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We could imagine notations that Pocomath could support that would simplify
|
||||||
|
* the above, maybe something like
|
||||||
|
* 'Complex<T>': ({
|
||||||
|
* 'self(T): U': absq,
|
||||||
|
* 'add(U,U):V': plus,
|
||||||
|
* V
|
||||||
|
* }) => Returns(V, z => plus(absq(z.re), absq(z.im)))
|
||||||
|
*/
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
|
import Returns from '../core/Returns.mjs'
|
||||||
export * from './Types/Complex.mjs'
|
export * from './Types/Complex.mjs'
|
||||||
|
|
||||||
export const multiply = {
|
export const multiply = {
|
||||||
'Complex<T>,Complex<T>': ({
|
'Complex<T>,Complex<T>': ({
|
||||||
|
T,
|
||||||
'complex(T,T)': cplx,
|
'complex(T,T)': cplx,
|
||||||
'add(T,T)': plus,
|
'add(T,T)': plus,
|
||||||
'subtract(T,T)': sub,
|
'subtract(T,T)': sub,
|
||||||
'self(T,T)': me,
|
'self(T,T)': me,
|
||||||
'conjugate(T)': conj // makes quaternion multiplication work
|
'conjugate(T)': conj // makes quaternion multiplication work
|
||||||
}) => (w,z) => {
|
}) => Returns(
|
||||||
return cplx(
|
`Complex<${T}>`,
|
||||||
|
(w,z) => cplx(
|
||||||
sub(me(w.re, z.re), me(conj(w.im), z.im)),
|
sub(me(w.re, z.re), me(conj(w.im), z.im)),
|
||||||
plus(me(conj(w.re), z.im), me(w.im, z.re)))
|
plus(me(conj(w.re), z.im), me(w.im, z.re)))
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import {Returns, returnTypeOf} from '../core/Returns.mjs'
|
||||||
export * from './Types/Complex.mjs'
|
export * from './Types/Complex.mjs'
|
||||||
|
|
||||||
export const sqrt = {
|
export const sqrt = {
|
||||||
@ -12,29 +13,41 @@ export const sqrt = {
|
|||||||
'multiply(T,T)': mult,
|
'multiply(T,T)': mult,
|
||||||
'self(T)': me,
|
'self(T)': me,
|
||||||
'divide(T,T)': div,
|
'divide(T,T)': div,
|
||||||
'abs(Complex<T>)': absC,
|
'absquare(Complex<T>)': absqC,
|
||||||
'subtract(T,T)': sub
|
'subtract(T,T)': sub
|
||||||
}) => {
|
}) => {
|
||||||
|
let baseReturns = returnTypeOf(me)
|
||||||
|
if (baseReturns.includes('|')) {
|
||||||
|
// Bit of a hack, because it is relying on other implementations
|
||||||
|
// to list the "typical" value of sqrt first
|
||||||
|
baseReturns = baseReturns.split('|', 1)[0]
|
||||||
|
}
|
||||||
|
|
||||||
if (config.predictable) {
|
if (config.predictable) {
|
||||||
return z => {
|
return Returns(`Complex<${baseReturns}>`, z => {
|
||||||
const reOne = uno(z.re)
|
const reOne = uno(z.re)
|
||||||
if (isZ(z.im) && sgn(z.re) === reOne) return cplxU(me(z.re))
|
if (isZ(z.im) && sgn(z.re) === reOne) return cplxU(me(z.re))
|
||||||
const reTwo = plus(reOne, reOne)
|
const reTwo = plus(reOne, reOne)
|
||||||
|
const myabs = me(absqC(z))
|
||||||
return cplxB(
|
return cplxB(
|
||||||
mult(sgn(z.im), me(div(plus(absC(z),z.re), reTwo))),
|
mult(sgn(z.im), me(div(plus(myabs, z.re), reTwo))),
|
||||||
me(div(sub(absC(z),z.re), reTwo))
|
me(div(sub(myabs, z.re), reTwo))
|
||||||
)
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return Returns(
|
||||||
|
`Complex<${baseReturns}>|${baseReturns}|undefined`,
|
||||||
|
z => {
|
||||||
|
const reOne = uno(z.re)
|
||||||
|
if (isZ(z.im) && sgn(z.re) === reOne) return me(z.re)
|
||||||
|
const reTwo = plus(reOne, reOne)
|
||||||
|
const myabs = me(absqC(z))
|
||||||
|
const reSqrt = me(div(plus(myabs, z.re), reTwo))
|
||||||
|
const imSqrt = me(div(sub(myabs, z.re), reTwo))
|
||||||
|
if (reSqrt === undefined || imSqrt === undefined) return undefined
|
||||||
|
return cplxB(mult(sgn(z.im), reSqrt), imSqrt)
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
return z => {
|
|
||||||
const reOne = uno(z.re)
|
|
||||||
if (isZ(z.im) && sgn(z.re) === reOne) return me(z.re)
|
|
||||||
const reTwo = plus(reOne, reOne)
|
|
||||||
const reSqrt = me(div(plus(absC(z),z.re), reTwo))
|
|
||||||
const imSqrt = me(div(sub(absC(z),z.re), reTwo))
|
|
||||||
if (reSqrt === undefined || imSqrt === undefined) return undefined
|
|
||||||
return cplxB(mult(sgn(z.im), reSqrt), imSqrt)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ export default class PocomathInstance {
|
|||||||
'joinTypes',
|
'joinTypes',
|
||||||
'name',
|
'name',
|
||||||
'returnTypeOf',
|
'returnTypeOf',
|
||||||
|
'resolve',
|
||||||
'self',
|
'self',
|
||||||
'subtypesOf',
|
'subtypesOf',
|
||||||
'supertypesOf',
|
'supertypesOf',
|
||||||
@ -49,7 +50,8 @@ export default class PocomathInstance {
|
|||||||
|
|
||||||
constructor(name) {
|
constructor(name) {
|
||||||
this.name = name
|
this.name = name
|
||||||
this._imps = {}
|
this._imps = {} // Pocomath implementations, with dependencies
|
||||||
|
this._TFimps = {} // typed-function implementations, dependencies resolved
|
||||||
this._affects = {}
|
this._affects = {}
|
||||||
this._typed = typed.create()
|
this._typed = typed.create()
|
||||||
this._typed.clear()
|
this._typed.clear()
|
||||||
@ -220,7 +222,6 @@ export default class PocomathInstance {
|
|||||||
if (details) {
|
if (details) {
|
||||||
return returnTypeOf(details.fn, signature, this)
|
return returnTypeOf(details.fn, signature, this)
|
||||||
}
|
}
|
||||||
console.log('Checking return type of', operation)
|
|
||||||
return returnTypeOf(this[operation], signature, this)
|
return returnTypeOf(this[operation], signature, this)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -564,8 +565,28 @@ export default class PocomathInstance {
|
|||||||
`Conflicting definitions of ${signature} for ${name}`)
|
`Conflicting definitions of ${signature} for ${name}`)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Must avoid aliasing into another instance:
|
/* Check if it's an ordinary non-template signature */
|
||||||
opImps[signature] = {uses: behavior.uses, does: behavior.does}
|
let explicit = true
|
||||||
|
for (const type of typesOfSignature(signature)) {
|
||||||
|
for (const word of type.split(/[<>:\s]/)) {
|
||||||
|
if (this._templateParam(word)) {
|
||||||
|
explicit = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!explicit) break
|
||||||
|
}
|
||||||
|
opImps[signature] = {
|
||||||
|
explicit,
|
||||||
|
uses: behavior.uses,
|
||||||
|
does: behavior.does
|
||||||
|
}
|
||||||
|
if (explicit) {
|
||||||
|
opImps[signature].resolved = false
|
||||||
|
} else {
|
||||||
|
opImps[signature].hasInstantiations = {}
|
||||||
|
opImps[signature].needsInstantiations = new Set()
|
||||||
|
}
|
||||||
for (const dep of behavior.uses) {
|
for (const dep of behavior.uses) {
|
||||||
const depname = dep.split('(', 1)[0]
|
const depname = dep.split('(', 1)[0]
|
||||||
if (depname === 'self' || this._templateParam(depname)) {
|
if (depname === 'self' || this._templateParam(depname)) {
|
||||||
@ -604,11 +625,40 @@ export default class PocomathInstance {
|
|||||||
* Reset an operation to require creation of typed-function,
|
* Reset an operation to require creation of typed-function,
|
||||||
* and if it has no implementations so far, set them up.
|
* and if it has no implementations so far, set them up.
|
||||||
*/
|
*/
|
||||||
_invalidate(name) {
|
_invalidate(name, reason) {
|
||||||
if (this._invalid.has(name)) return
|
|
||||||
if (!(name in this._imps)) {
|
if (!(name in this._imps)) {
|
||||||
this._imps[name] = {}
|
this._imps[name] = {}
|
||||||
}
|
}
|
||||||
|
if (reason) {
|
||||||
|
// Make sure no TF imps that depend on reason remain:
|
||||||
|
for (const [signature, behavior] of Object.entries(this._imps[name])) {
|
||||||
|
let invalidated = false
|
||||||
|
if (reason.charAt(0) === ':') {
|
||||||
|
const badType = reason.slice(1)
|
||||||
|
if (signature.includes(badType)) invalidated = true
|
||||||
|
} else {
|
||||||
|
for (const dep of behavior.uses) {
|
||||||
|
if (dep.includes(reason)) {
|
||||||
|
invalidated = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (invalidated) {
|
||||||
|
if (behavior.explicit) {
|
||||||
|
if (behavior.resolved) delete this._TFimps[signature]
|
||||||
|
behavior.resolved = false
|
||||||
|
} else {
|
||||||
|
for (const fullSig
|
||||||
|
of Object.values(behavior.hasInstantiations)) {
|
||||||
|
delete this._TFimps[fullSig]
|
||||||
|
}
|
||||||
|
behavior.hasInstantiations = {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this._invalid.has(name)) return
|
||||||
this._invalid.add(name)
|
this._invalid.add(name)
|
||||||
this._invalidateDependents(name)
|
this._invalidateDependents(name)
|
||||||
const self = this
|
const self = this
|
||||||
@ -628,7 +678,7 @@ export default class PocomathInstance {
|
|||||||
_invalidateDependents(name) {
|
_invalidateDependents(name) {
|
||||||
if (name in this._affects) {
|
if (name in this._affects) {
|
||||||
for (const ancestor of this._affects[name]) {
|
for (const ancestor of this._affects[name]) {
|
||||||
this._invalidate(ancestor)
|
this._invalidate(ancestor, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -642,6 +692,10 @@ export default class PocomathInstance {
|
|||||||
if (!imps) {
|
if (!imps) {
|
||||||
throw new SyntaxError(`No implementations for ${name}`)
|
throw new SyntaxError(`No implementations for ${name}`)
|
||||||
}
|
}
|
||||||
|
if (!(this._TFimps[name])) {
|
||||||
|
this._TFimps[name] = {}
|
||||||
|
}
|
||||||
|
const tf_imps = this._TFimps[name]
|
||||||
/* Collect the entries we know the types for */
|
/* Collect the entries we know the types for */
|
||||||
const usableEntries = []
|
const usableEntries = []
|
||||||
for (const entry of Object.entries(imps)) {
|
for (const entry of Object.entries(imps)) {
|
||||||
@ -664,20 +718,13 @@ export default class PocomathInstance {
|
|||||||
* in the midst of being reassembled
|
* in the midst of being reassembled
|
||||||
*/
|
*/
|
||||||
Object.defineProperty(this, name, {configurable: true, value: 'limbo'})
|
Object.defineProperty(this, name, {configurable: true, value: 'limbo'})
|
||||||
const tf_imps = {}
|
|
||||||
for (const [rawSignature, behavior] of usableEntries) {
|
for (const [rawSignature, behavior] of usableEntries) {
|
||||||
/* Check if it's an ordinary non-template signature */
|
if (behavior.explicit) {
|
||||||
let explicit = true
|
if (!(behavior.resolved)) {
|
||||||
for (const type of typesOfSignature(rawSignature)) {
|
this._addTFimplementation(tf_imps, rawSignature, behavior)
|
||||||
for (const word of type.split(/[<>:\s]/)) {
|
tf_imps[rawSignature]._pocoSignature = rawSignature
|
||||||
if (this._templateParam(word)) {
|
behavior.resolved = true
|
||||||
explicit = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (explicit) {
|
|
||||||
this._addTFimplementation(tf_imps, rawSignature, behavior)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
/* It's a template, have to instantiate */
|
/* It's a template, have to instantiate */
|
||||||
@ -693,12 +740,9 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* First, add the known instantiations, gathering all types needed */
|
/* First, add the known instantiations, gathering all types needed */
|
||||||
if (!('instantiations' in behavior)) {
|
if (ubType) behavior.needsInstantiations.add(ubType)
|
||||||
behavior.instantiations = new Set()
|
|
||||||
if (ubType) behavior.instantiations.add(ubType)
|
|
||||||
}
|
|
||||||
let instantiationSet = new Set()
|
let instantiationSet = new Set()
|
||||||
for (const instType of behavior.instantiations) {
|
for (const instType of behavior.needsInstantiations) {
|
||||||
instantiationSet.add(instType)
|
instantiationSet.add(instType)
|
||||||
const otherTypes =
|
const otherTypes =
|
||||||
ubType ? this.subtypesOf(instType) : this._priorTypes[instType]
|
ubType ? this.subtypesOf(instType) : this._priorTypes[instType]
|
||||||
@ -710,6 +754,7 @@ export default class PocomathInstance {
|
|||||||
for (const instType of instantiationSet) {
|
for (const instType of instantiationSet) {
|
||||||
if (!(instType in this.Types)) continue
|
if (!(instType in this.Types)) continue
|
||||||
if (this.Types[instType] === anySpec) continue
|
if (this.Types[instType] === anySpec) continue
|
||||||
|
if (instType in behavior.hasInstantiations) continue
|
||||||
const signature =
|
const signature =
|
||||||
substituteInSignature(rawSignature, theTemplateParam, instType)
|
substituteInSignature(rawSignature, theTemplateParam, instType)
|
||||||
/* Don't override an explicit implementation: */
|
/* Don't override an explicit implementation: */
|
||||||
@ -742,10 +787,14 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
this._addTFimplementation(
|
this._addTFimplementation(
|
||||||
tf_imps, signature, {uses, does: patch})
|
tf_imps, signature, {uses, does: patch})
|
||||||
|
tf_imps[signature]._pocoSignature = rawSignature
|
||||||
|
tf_imps[signature]._pocoInstance = instType
|
||||||
|
behavior.hasInstantiations[instType] = signature
|
||||||
}
|
}
|
||||||
/* Now add the catchall signature */
|
/* Now add the catchall signature */
|
||||||
/* (Not needed if if it's a bounded template) */
|
/* (Not needed if if it's a bounded template) */
|
||||||
if (ubType) continue
|
if (ubType) continue
|
||||||
|
if ('_catchall_' in behavior.hasInstantiations) continue
|
||||||
let templateCall = `<${theTemplateParam}>`
|
let templateCall = `<${theTemplateParam}>`
|
||||||
/* Relying here that the base of 'Foo<T>' is 'Foo': */
|
/* Relying here that the base of 'Foo<T>' is 'Foo': */
|
||||||
let baseSignature = rawSignature.replaceAll(templateCall, '')
|
let baseSignature = rawSignature.replaceAll(templateCall, '')
|
||||||
@ -886,11 +935,11 @@ export default class PocomathInstance {
|
|||||||
/* Arrange that the desired instantiation will be there next
|
/* Arrange that the desired instantiation will be there next
|
||||||
* time so we don't have to go through that again for this type
|
* time so we don't have to go through that again for this type
|
||||||
*/
|
*/
|
||||||
refs[theTemplateParam] = instantiateFor
|
behavior.needsInstantiations.add(instantiateFor)
|
||||||
behavior.instantiations.add(instantiateFor)
|
|
||||||
self._invalidate(name)
|
self._invalidate(name)
|
||||||
// And update refs because we now know the type we're instantiating
|
// And update refs because we now know the type we're instantiating
|
||||||
// for:
|
// for:
|
||||||
|
refs[theTemplateParam] = instantiateFor
|
||||||
const innerRefs = {}
|
const innerRefs = {}
|
||||||
for (const dep in simplifiedUses) {
|
for (const dep in simplifiedUses) {
|
||||||
const simplifiedDep = simplifiedUses[dep]
|
const simplifiedDep = simplifiedUses[dep]
|
||||||
@ -903,7 +952,7 @@ export default class PocomathInstance {
|
|||||||
needsig, theTemplateParam, instantiateFor)
|
needsig, theTemplateParam, instantiateFor)
|
||||||
let resname = simplifiedDep
|
let resname = simplifiedDep
|
||||||
if (resname == 'self') resname = name
|
if (resname == 'self') resname = name
|
||||||
innerRefs[dep] = self._pocoresolve(
|
innerRefs[dep] = self.resolve(
|
||||||
resname, subsig, refs[simplifiedDep])
|
resname, subsig, refs[simplifiedDep])
|
||||||
} else {
|
} else {
|
||||||
innerRefs[dep] = refs[simplifiedDep]
|
innerRefs[dep] = refs[simplifiedDep]
|
||||||
@ -913,13 +962,15 @@ export default class PocomathInstance {
|
|||||||
// Finally ready to make the call.
|
// Finally ready to make the call.
|
||||||
const implementation = behavior.does(innerRefs)
|
const implementation = behavior.does(innerRefs)
|
||||||
// We can access return type information here
|
// We can access return type information here
|
||||||
// And in particular, if it's a template, we should try to
|
// And in particular, if it might be a template, we should try to
|
||||||
// instantiate it:
|
// instantiate it:
|
||||||
const returnType = returnTypeOf(implementation, wantSig, self)
|
const returnType = returnTypeOf(implementation, wantSig, self)
|
||||||
const instantiated = self._maybeInstantiate(returnType)
|
for (const possibility of returnType.split('|')) {
|
||||||
if (instantiated) {
|
const instantiated = self._maybeInstantiate(possibility)
|
||||||
const tempBase = instantiated.split('<',1)[0]
|
if (instantiated) {
|
||||||
self._invalidateDependents(':' + tempBase)
|
const tempBase = instantiated.split('<',1)[0]
|
||||||
|
self._invalidateDependents(':' + tempBase)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return implementation(...args)
|
return implementation(...args)
|
||||||
}
|
}
|
||||||
@ -932,6 +983,7 @@ export default class PocomathInstance {
|
|||||||
const outerUses = new Set(Object.values(simplifiedUses))
|
const outerUses = new Set(Object.values(simplifiedUses))
|
||||||
this._addTFimplementation(
|
this._addTFimplementation(
|
||||||
tf_imps, signature, {uses: outerUses, does: patch})
|
tf_imps, signature, {uses: outerUses, does: patch})
|
||||||
|
behavior.hasInstantiations._catchall_ = rawSignature
|
||||||
}
|
}
|
||||||
this._correctPartialSelfRefs(name, tf_imps)
|
this._correctPartialSelfRefs(name, tf_imps)
|
||||||
// Make sure we have all of the needed (template) types; and if they
|
// Make sure we have all of the needed (template) types; and if they
|
||||||
@ -946,9 +998,17 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const badSig of badSigs) {
|
for (const badSig of badSigs) {
|
||||||
|
const imp = tf_imps[badSig]
|
||||||
delete tf_imps[badSig]
|
delete tf_imps[badSig]
|
||||||
|
const fromBehavior = this._imps[name][imp._pocoSignature]
|
||||||
|
if (fromBehavior.explicit) {
|
||||||
|
fromBehavior.resolved = false
|
||||||
|
} else {
|
||||||
|
delete fromBehavior.hasInstantiations[imp._pocoInstance]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const tf = this._typed(name, tf_imps)
|
const tf = this._typed(name, tf_imps)
|
||||||
|
Object.defineProperty(tf, 'fromInstance', {value: this})
|
||||||
Object.defineProperty(this, name, {configurable: true, value: tf})
|
Object.defineProperty(this, name, {configurable: true, value: tf})
|
||||||
return tf
|
return tf
|
||||||
}
|
}
|
||||||
@ -1006,13 +1066,20 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
if (func === 'self') {
|
if (func === 'self') {
|
||||||
if (needsig) {
|
if (needsig) {
|
||||||
if (full_self_referential) {
|
/* Maybe we can resolve the self reference without troubling
|
||||||
throw new SyntaxError(
|
* typed-function:
|
||||||
'typed-function does not support mixed full and '
|
*/
|
||||||
+ 'partial self-reference')
|
if (needsig in imps && typeof imps[needsig] == 'function') {
|
||||||
}
|
refs[dep] = imps[needsig]
|
||||||
if (subsetOfKeys(typesOfSignature(needsig), this.Types)) {
|
} else {
|
||||||
part_self_references.push(needsig)
|
if (full_self_referential) {
|
||||||
|
throw new SyntaxError(
|
||||||
|
'typed-function does not support mixed full and '
|
||||||
|
+ 'partial self-reference')
|
||||||
|
}
|
||||||
|
if (subsetOfKeys(typesOfSignature(needsig), this.Types)) {
|
||||||
|
part_self_references.push(needsig)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (part_self_references.length) {
|
if (part_self_references.length) {
|
||||||
@ -1024,19 +1091,41 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this[func] === 'limbo') {
|
if (this[func] === 'limbo') {
|
||||||
/* We are in the midst of bundling func, so have to use
|
/* We are in the midst of bundling func */
|
||||||
* an indirect reference to func. And given that, there's
|
let fallback = true
|
||||||
* really no helpful way to extract a specific signature
|
/* So the first thing we can do is try the tf_imps we are
|
||||||
|
* accumulating:
|
||||||
*/
|
*/
|
||||||
const self = this
|
if (needsig) {
|
||||||
refs[dep] = function () { // is this the most efficient?
|
const tempTF = this._typed('dummy_' + func, this._TFimps[func])
|
||||||
return self[func].apply(this, arguments)
|
let result = undefined
|
||||||
|
try {
|
||||||
|
result = this._typed.find(tempTF, needsig, {exact: true})
|
||||||
|
} catch {}
|
||||||
|
if (result) {
|
||||||
|
refs[dep] = result
|
||||||
|
fallback = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fallback) {
|
||||||
|
/* Either we need the whole function or the signature
|
||||||
|
* we need is not available yet, so we have to use
|
||||||
|
* an indirect reference to func. And given that, there's
|
||||||
|
* really no helpful way to extract a specific signature
|
||||||
|
*/
|
||||||
|
const self = this
|
||||||
|
const redirect = function () { // is this the most efficient?
|
||||||
|
return self[func].apply(this, arguments)
|
||||||
|
}
|
||||||
|
Object.defineProperty(redirect, 'name', {value: func})
|
||||||
|
Object.defineProperty(redirect, 'fromInstance', {value: this})
|
||||||
|
refs[dep] = redirect
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// can bundle up func, and grab its signature if need be
|
// can bundle up func, and grab its signature if need be
|
||||||
let destination = this[func]
|
let destination = this[func]
|
||||||
if (destination && needsig) {
|
if (destination && needsig) {
|
||||||
destination = this._pocoresolve(func, needsig)
|
destination = this.resolve(func, needsig)
|
||||||
}
|
}
|
||||||
refs[dep] = destination
|
refs[dep] = destination
|
||||||
}
|
}
|
||||||
@ -1076,7 +1165,8 @@ export default class PocomathInstance {
|
|||||||
_correctPartialSelfRefs(name, imps) {
|
_correctPartialSelfRefs(name, imps) {
|
||||||
for (const aSignature in imps) {
|
for (const aSignature in imps) {
|
||||||
if (!(imps[aSignature].deferred)) continue
|
if (!(imps[aSignature].deferred)) continue
|
||||||
const part_self_references = imps[aSignature].psr
|
const deferral = imps[aSignature]
|
||||||
|
const part_self_references = deferral.psr
|
||||||
const corrected_self_references = []
|
const corrected_self_references = []
|
||||||
for (const neededSig of part_self_references) {
|
for (const neededSig of part_self_references) {
|
||||||
// Have to find a match for neededSig among the other signatures
|
// Have to find a match for neededSig among the other signatures
|
||||||
@ -1098,8 +1188,8 @@ export default class PocomathInstance {
|
|||||||
+ `${name}(${neededSig})`)
|
+ `${name}(${neededSig})`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const refs = imps[aSignature].builtRefs
|
const refs = deferral.builtRefs
|
||||||
const does = imps[aSignature].sigDoes
|
const does = deferral.sigDoes
|
||||||
imps[aSignature] = this._typed.referTo(
|
imps[aSignature] = this._typed.referTo(
|
||||||
...corrected_self_references, (...impls) => {
|
...corrected_self_references, (...impls) => {
|
||||||
for (let i = 0; i < part_self_references.length; ++i) {
|
for (let i = 0; i < part_self_references.length; ++i) {
|
||||||
@ -1110,6 +1200,8 @@ export default class PocomathInstance {
|
|||||||
return implementation
|
return implementation
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
imps[aSignature]._pocoSignature = deferral._pocoSignature
|
||||||
|
imps[aSignature]._pocoInstance = deferral._pocoInstance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1282,16 +1374,30 @@ export default class PocomathInstance {
|
|||||||
typedFunction = this[name]
|
typedFunction = this[name]
|
||||||
}
|
}
|
||||||
let result = undefined
|
let result = undefined
|
||||||
if (!this._typed.isTypedFunction(typedFunction)) {
|
const haveTF = this._typed.isTypedFunction(typedFunction)
|
||||||
return result
|
if (haveTF) {
|
||||||
|
try {
|
||||||
|
result = this._typed.findSignature(typedFunction, sig, {exact: true})
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try {
|
if (result || !(this._imps[name])) return result
|
||||||
result = this._typed.findSignature(typedFunction, sig, {exact: true})
|
|
||||||
} catch {
|
|
||||||
}
|
|
||||||
if (result) return result
|
|
||||||
const foundsig = this._findSubtypeImpl(name, this._imps[name], sig)
|
const foundsig = this._findSubtypeImpl(name, this._imps[name], sig)
|
||||||
if (foundsig) return this._typed.findSignature(typedFunction, foundsig)
|
if (foundsig) {
|
||||||
|
if (haveTF) {
|
||||||
|
return this._typed.findSignature(typedFunction, foundsig)
|
||||||
|
}
|
||||||
|
// We have an implementation but not a typed function. Do the best
|
||||||
|
// we can:
|
||||||
|
const foundImpl = this._imps[name][foundsig]
|
||||||
|
const needs = {}
|
||||||
|
for (const dep of foundImpl.uses) {
|
||||||
|
const [base, sig] = dep.split('()')
|
||||||
|
needs[dep] = this.resolve(base, sig)
|
||||||
|
}
|
||||||
|
const pseudoImpl = foundImpl.does(needs)
|
||||||
|
return {fn: pseudoImpl, implementation: pseudoImpl}
|
||||||
|
}
|
||||||
const wantTypes = typeListOfSignature(sig)
|
const wantTypes = typeListOfSignature(sig)
|
||||||
for (const [implSig, details]
|
for (const [implSig, details]
|
||||||
of typedFunction._typedFunctionData.signatureMap) {
|
of typedFunction._typedFunctionData.signatureMap) {
|
||||||
@ -1314,7 +1420,12 @@ export default class PocomathInstance {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
_pocoresolve(name, sig, typedFunction) {
|
/* Returns a function that implements the operation with the given name
|
||||||
|
* when called with the given signature. The optional third argument is
|
||||||
|
* the typed function that provides the operation name, which can be
|
||||||
|
* passed in for efficiency if it is already available.
|
||||||
|
*/
|
||||||
|
resolve = Returns('function', function (name, sig, typedFunction) {
|
||||||
if (!this._typed.isTypedFunction(typedFunction)) {
|
if (!this._typed.isTypedFunction(typedFunction)) {
|
||||||
typedFunction = this[name]
|
typedFunction = this[name]
|
||||||
}
|
}
|
||||||
@ -1323,6 +1434,6 @@ export default class PocomathInstance {
|
|||||||
// total punt, revert to typed-function resolution on every call;
|
// total punt, revert to typed-function resolution on every call;
|
||||||
// hopefully this happens rarely:
|
// hopefully this happens rarely:
|
||||||
return typedFunction
|
return typedFunction
|
||||||
}
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
|
import Returns from '../core/Returns.mjs'
|
||||||
|
|
||||||
export const absquare = {
|
export const absquare = {
|
||||||
T: ({
|
T: ({
|
||||||
|
T,
|
||||||
'square(T)': sq,
|
'square(T)': sq,
|
||||||
'abs(T)': abval
|
'abs(T)': abval
|
||||||
}) => t => sq(abval(t))
|
}) => Returns(T, t => sq(abval(t)))
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import {Returns, returnTypeOf} from '../core/Returns.mjs'
|
||||||
|
|
||||||
export const square = {
|
export const square = {
|
||||||
T: ({'multiply(T,T)': multT}) => x => multT(x,x)
|
T: ({'multiply(T,T)': multT}) => Returns(
|
||||||
|
returnTypeOf(multT), x => multT(x,x))
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
import Returns from '../core/Returns.mjs'
|
||||||
export * from './Types/number.mjs'
|
export * from './Types/number.mjs'
|
||||||
|
|
||||||
/* Absolute value squared */
|
/* Absolute value squared */
|
||||||
export const absquare = {
|
export const absquare = {
|
||||||
number: ({'square(number)': sqn}) => n => sqn(n)
|
'T:number': ({T, 'square(T)': sqn}) => Returns(T, n => sqn(n))
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import Returns from '../core/Returns.mjs'
|
||||||
|
|
||||||
export * from './Types/number.mjs'
|
export * from './Types/number.mjs'
|
||||||
|
|
||||||
export const multiply = {'number,number': () => (m,n) => m*n}
|
export const multiply = {'T:number,T': ({T}) => Returns(T, (m,n) => m*n)}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import Returns from '../core/Returns.mjs'
|
||||||
export * from './Types/number.mjs'
|
export * from './Types/number.mjs'
|
||||||
|
|
||||||
export const sqrt = {
|
export const sqrt = {
|
||||||
@ -5,13 +6,13 @@ export const sqrt = {
|
|||||||
config,
|
config,
|
||||||
'complex(number,number)': cplx,
|
'complex(number,number)': cplx,
|
||||||
'negate(number)': neg}) => {
|
'negate(number)': neg}) => {
|
||||||
if (config.predictable || !cplx) {
|
if (config.predictable || !cplx) {
|
||||||
return n => isNaN(n) ? NaN : Math.sqrt(n)
|
return Returns('number', n => isNaN(n) ? NaN : Math.sqrt(n))
|
||||||
|
}
|
||||||
|
return Returns('number|Complex<number>', n => {
|
||||||
|
if (isNaN(n)) return NaN
|
||||||
|
if (n >= 0) return Math.sqrt(n)
|
||||||
|
return cplx(0, Math.sqrt(neg(n)))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return n => {
|
|
||||||
if (isNaN(n)) return NaN
|
|
||||||
if (n >= 0) return Math.sqrt(n)
|
|
||||||
return cplx(0, Math.sqrt(neg(n)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,7 @@ describe('complex', () => {
|
|||||||
assert.deepStrictEqual(
|
assert.deepStrictEqual(
|
||||||
math.multiply(q0, math.quaternion(2, 1, 0.1, 0.1)),
|
math.multiply(q0, math.quaternion(2, 1, 0.1, 0.1)),
|
||||||
math.quaternion(1.9, 1.1, 2.1, -0.9))
|
math.quaternion(1.9, 1.1, 2.1, -0.9))
|
||||||
|
math.absquare(math.complex(1.25, 2.5)) //HACK: need absquare(Complex<number>)
|
||||||
assert.strictEqual(math.abs(q0), Math.sqrt(2))
|
assert.strictEqual(math.abs(q0), Math.sqrt(2))
|
||||||
assert.strictEqual(math.abs(q1), Math.sqrt(33)/4)
|
assert.strictEqual(math.abs(q1), Math.sqrt(33)/4)
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user