feat(install): Allow plain functions
This commit is contained in:
parent
0ce4de086c
commit
8418817f9f
@ -1,6 +1,6 @@
|
|||||||
import PocomathInstance from '../core/PocomathInstance.mjs'
|
import PocomathInstance from '../core/PocomathInstance.mjs'
|
||||||
import * as bigints from './native.mjs'
|
import * as bigints from './native.mjs'
|
||||||
import * as generic from '../generic/all.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
|
return true // successful
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
this._plainFunctions = new Set() // the names of the plain functions
|
||||||
this._chainRepository = {} // place to store chainified functions
|
this._chainRepository = {} // place to store chainified functions
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,6 +137,8 @@ export default class PocomathInstance {
|
|||||||
for (const [item, spec] of Object.entries(ops)) {
|
for (const [item, spec] of Object.entries(ops)) {
|
||||||
if (spec instanceof PocomathInstance) {
|
if (spec instanceof PocomathInstance) {
|
||||||
this._installInstance(spec)
|
this._installInstance(spec)
|
||||||
|
} else if (typeof spec === 'function') {
|
||||||
|
stdFunctions[item] = spec
|
||||||
} else {
|
} else {
|
||||||
if (item.charAt(0) === '_') {
|
if (item.charAt(0) === '_') {
|
||||||
throw new SyntaxError(
|
throw new SyntaxError(
|
||||||
@ -183,6 +186,9 @@ export default class PocomathInstance {
|
|||||||
migrateImps[operator] = other._imps[operator]
|
migrateImps[operator] = other._imps[operator]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (const plain of other._plainFunctions) {
|
||||||
|
migrateImps[plain] = other[plain]
|
||||||
|
}
|
||||||
this._installFunctions(migrateImps)
|
this._installFunctions(migrateImps)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,7 +358,21 @@ export default class PocomathInstance {
|
|||||||
/* Used internally by install, see the documentation there */
|
/* Used internally by install, see the documentation there */
|
||||||
_installFunctions(functions) {
|
_installFunctions(functions) {
|
||||||
for (const [name, spec] of Object.entries(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)
|
this._invalidate(name)
|
||||||
const opImps = this._imps[name]
|
const opImps = this._imps[name]
|
||||||
for (const [signature, behavior] of Object.entries(spec)) {
|
for (const [signature, behavior] of Object.entries(spec)) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import PocomathInstance from '../core/PocomathInstance.mjs'
|
import PocomathInstance from '../core/PocomathInstance.mjs'
|
||||||
import * as numbers from './native.mjs'
|
import * as numbers from './native.mjs'
|
||||||
import * as generic from '../generic/all.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 bigints from './bigint/native.mjs'
|
||||||
import * as complex from './complex/native.mjs'
|
import * as complex from './complex/native.mjs'
|
||||||
import * as generic from './generic/all.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(
|
const math = PocomathInstance.merge(
|
||||||
'math', numbers, bigints, complex, generic, floor)
|
'math', numbers, bigints, complex, generic, ops)
|
||||||
|
|
||||||
export default math
|
export default math
|
||||||
|
@ -93,4 +93,14 @@ describe('The default full pocomath instance "math"', () => {
|
|||||||
assert.throws(() => math.chain(3).foo(), /Unknown operation/)
|
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