feat(install): Allow plain functions #44
@ -1,6 +1,6 @@
|
||||
import PocomathInstance from '../core/PocomathInstance.mjs'
|
||||
import * as bigints from './native.mjs'
|
||||
import * as generic from '../generic/all.mjs'
|
||||
import * as floor from '../ops/floor.mjs'
|
||||
import * as ops from '../ops/all.mjs'
|
||||
|
||||
export default PocomathInstance.merge('bigint', bigints, generic, floor)
|
||||
export default PocomathInstance.merge('bigint', bigints, generic, ops)
|
||||
|
@ -66,6 +66,7 @@ export default class PocomathInstance {
|
||||
return true // successful
|
||||
}
|
||||
})
|
||||
this._plainFunctions = new Set() // the names of the plain functions
|
||||
this._chainRepository = {} // place to store chainified functions
|
||||
}
|
||||
|
||||
@ -136,6 +137,8 @@ export default class PocomathInstance {
|
||||
for (const [item, spec] of Object.entries(ops)) {
|
||||
if (spec instanceof PocomathInstance) {
|
||||
this._installInstance(spec)
|
||||
} else if (typeof spec === 'function') {
|
||||
stdFunctions[item] = spec
|
||||
} else {
|
||||
if (item.charAt(0) === '_') {
|
||||
throw new SyntaxError(
|
||||
@ -183,6 +186,9 @@ export default class PocomathInstance {
|
||||
migrateImps[operator] = other._imps[operator]
|
||||
}
|
||||
}
|
||||
for (const plain of other._plainFunctions) {
|
||||
migrateImps[plain] = other[plain]
|
||||
}
|
||||
this._installFunctions(migrateImps)
|
||||
}
|
||||
|
||||
@ -352,7 +358,21 @@ export default class PocomathInstance {
|
||||
/* Used internally by install, see the documentation there */
|
||||
_installFunctions(functions) {
|
||||
for (const [name, spec] of Object.entries(functions)) {
|
||||
// new implementations, so set the op up to lazily recreate itself
|
||||
if (typeof spec === 'function') {
|
||||
if (name in this) {
|
||||
if (spec === this[name]) continue
|
||||
throw new SyntaxError(`Attempt to redefine function ${name}`)
|
||||
}
|
||||
this._plainFunctions.add(name)
|
||||
this[name] = spec
|
||||
continue
|
||||
}
|
||||
// new implementations, first check the name isn't taken
|
||||
if (this._plainFunctions.has(name)) {
|
||||
throw new SyntaxError(
|
||||
`Can't add implementations to function ${name}`)
|
||||
}
|
||||
// All clear, so set the op up to lazily recreate itself
|
||||
this._invalidate(name)
|
||||
const opImps = this._imps[name]
|
||||
for (const [signature, behavior] of Object.entries(spec)) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import PocomathInstance from '../core/PocomathInstance.mjs'
|
||||
import * as numbers from './native.mjs'
|
||||
import * as generic from '../generic/all.mjs'
|
||||
import * as floor from '../ops/floor.mjs'
|
||||
import * as ops from '../ops/all.mjs'
|
||||
|
||||
export default PocomathInstance.merge('number', numbers, generic, floor)
|
||||
export default PocomathInstance.merge('number', numbers, generic, ops)
|
||||
|
||||
|
4
src/ops/all.mjs
Normal file
4
src/ops/all.mjs
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './choose.mjs'
|
||||
export * from './factorial.mjs'
|
||||
export * from './floor.mjs'
|
||||
|
11
src/ops/choose.mjs
Normal file
11
src/ops/choose.mjs
Normal file
@ -0,0 +1,11 @@
|
||||
/* Note this is not a good algorithm for computing binomial coefficients,
|
||||
* it's just for demonstration purposes
|
||||
*/
|
||||
export const choose = {
|
||||
'NumInt,NumInt': ({factorial}) => (n,k) => Number(
|
||||
factorial(n) / (factorial(k)*factorial(n-k))),
|
||||
'bigint,bigint': ({
|
||||
factorial
|
||||
}) => (n,k) => factorial(n) / (factorial(k)*factorial(n-k))
|
||||
}
|
||||
|
8
src/ops/factorial.mjs
Normal file
8
src/ops/factorial.mjs
Normal file
@ -0,0 +1,8 @@
|
||||
export function factorial(n) {
|
||||
n = BigInt(n)
|
||||
let prod = 1n
|
||||
for (let i = n; i > 1n; --i) {
|
||||
prod *= i
|
||||
}
|
||||
return prod
|
||||
}
|
@ -4,9 +4,9 @@ import * as numbers from './number/native.mjs'
|
||||
import * as bigints from './bigint/native.mjs'
|
||||
import * as complex from './complex/native.mjs'
|
||||
import * as generic from './generic/all.mjs'
|
||||
import * as floor from './ops/floor.mjs'
|
||||
import * as ops from './ops/all.mjs'
|
||||
|
||||
const math = PocomathInstance.merge(
|
||||
'math', numbers, bigints, complex, generic, floor)
|
||||
'math', numbers, bigints, complex, generic, ops)
|
||||
|
||||
export default math
|
||||
|
@ -93,4 +93,14 @@ describe('The default full pocomath instance "math"', () => {
|
||||
assert.throws(() => math.chain(3).foo(), /Unknown operation/)
|
||||
})
|
||||
|
||||
it('calls plain factorial function', () => {
|
||||
assert.strictEqual(math.factorial(4), 24n)
|
||||
assert.strictEqual(math.factorial(7n), 5040n)
|
||||
})
|
||||
|
||||
it('calculates binomial coefficients', () => {
|
||||
assert.strictEqual(math.choose(6, 3), 20)
|
||||
assert.strictEqual(math.choose(21n, 2n), 210n)
|
||||
})
|
||||
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user