feat: Allow self-reference in implementations #4
@ -5,6 +5,7 @@ export default class PocomathInstance {
|
|||||||
constructor(name) {
|
constructor(name) {
|
||||||
this.name = name
|
this.name = name
|
||||||
this._imps = {}
|
this._imps = {}
|
||||||
|
this._affects = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,6 +47,14 @@ export default class PocomathInstance {
|
|||||||
`Conflicting definitions of ${signature} for ${name}`)
|
`Conflicting definitions of ${signature} for ${name}`)
|
||||||
} else {
|
} else {
|
||||||
opImps[signature] = implementations[signature]
|
opImps[signature] = implementations[signature]
|
||||||
|
for (const dep of implementations[signature][0]) {
|
||||||
|
const depname = dep.split('(', 1)[0]
|
||||||
|
if (depname === 'self') continue
|
||||||
|
if (!(depname in this._affects)) {
|
||||||
|
this._affects[depname] = new Set()
|
||||||
|
}
|
||||||
|
this._affects[depname].add(name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,6 +71,11 @@ export default class PocomathInstance {
|
|||||||
if (!(name in this._imps)) {
|
if (!(name in this._imps)) {
|
||||||
this._imps[name] = {}
|
this._imps[name] = {}
|
||||||
}
|
}
|
||||||
|
if (name in this._affects) {
|
||||||
|
for (const ancestor of this._affects[name]) {
|
||||||
|
this._invalidate(ancestor)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
import './Complex.mjs'
|
import {numComplex} from './Complex.mjs'
|
||||||
export const negate = {
|
export const negate = {
|
||||||
Complex: [['self'], ref => z => ({re: ref.self(z.re), im: ref.self(z.im)})]
|
/* need a "base case" to avoid infinite self-reference */
|
||||||
|
Complex: [['self'], ref => z => {
|
||||||
|
if (numComplex(z)) return {re: -z.re, im: -z.im}
|
||||||
|
return {re: ref.self(z.re), im: ref.self(z.im)}
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,16 @@ import typed from 'typed-function'
|
|||||||
import PocomathInstance from '../PocomathInstance.mjs'
|
import PocomathInstance from '../PocomathInstance.mjs'
|
||||||
import * as numbers from '../number/all.mjs'
|
import * as numbers from '../number/all.mjs'
|
||||||
import * as complex from '../complex/all.mjs'
|
import * as complex from '../complex/all.mjs'
|
||||||
|
import * as complexAdd from '../complex/add.mjs'
|
||||||
|
import * as complexNegate from '../complex/negate.mjs'
|
||||||
|
|
||||||
const bw = new PocomathInstance('backwards')
|
const bw = new PocomathInstance('backwards')
|
||||||
describe('A custom instance', () => {
|
describe('A custom instance', () => {
|
||||||
it("works when partially assembled", () => {
|
it("works when partially assembled", () => {
|
||||||
bw.install(complex)
|
bw.install(complex)
|
||||||
assert.deepStrictEqual(bw.add(2, bw.complex(0, 3)), {re: 2, im: 3})
|
assert.deepStrictEqual(bw.add(2, bw.complex(0, 3)), {re: 2, im: 3})
|
||||||
|
assert.deepStrictEqual(bw.negate(2), bw.complex(-2,-0))
|
||||||
|
assert.deepStrictEqual(bw.subtract(2, bw.complex(0, 3)), {re: 2, im: -3})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("can be assembled in any order", () => {
|
it("can be assembled in any order", () => {
|
||||||
@ -23,4 +27,15 @@ describe('A custom instance', () => {
|
|||||||
math.complex(11, -4)) // note both instances coexist
|
math.complex(11, -4)) // note both instances coexist
|
||||||
assert.deepStrictEqual(bw.negate(math.complex(3, '8')).im, -8)
|
assert.deepStrictEqual(bw.negate(math.complex(3, '8')).im, -8)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("can be assembled piecemeal", () => {
|
||||||
|
const pm = new PocomathInstance('piecemeal')
|
||||||
|
pm.install(numbers)
|
||||||
|
assert.strictEqual(pm.subtract(5, 10), -5)
|
||||||
|
pm.install(complexAdd)
|
||||||
|
pm.install(complexNegate)
|
||||||
|
// Should be enough to allow complex subtraction, as subtract is generic
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
pm.subtract({re:5, im:0}, {re:10, im:1}), {re:-5, im: -1})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user