From ac826916ecb02861ca7eb44e409b1a9c5c78a8a5 Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Tue, 19 Jul 2022 12:34:36 -0700 Subject: [PATCH] feat: Add all remaining features of original Picomath PoC --- README.md | 20 +++++++++++++++++++- test/_PocomathInstance.mjs | 13 +++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 test/_PocomathInstance.mjs diff --git a/README.md b/README.md index cfc8d61..0e985ce 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,21 @@ # pocomath -A little proof-of-concept for organizing mathjs by module inclusion, avoiding factory functions. \ No newline at end of file +A little proof-of-concept for organizing mathjs by module inclusion, avoiding factory functions. + +Note this project is package-managed by [pnpm](https://pnpm.io/). I do not expect that a clone can easily be manipulated with `npm`. + +Defines a class PocomathInstance to embody independent instances of a mathjs-style CAS. Basically, it keeps track of a collection of implementations (in the sense of typed-function) for each of the functions to be used in the CAS, rather than just the finalized typed-functions. It also tracks the dependencies of each implementation (which must form a directed acyclic network). When a method is requested from the instance, it assembles the proper typed-function (and caches it, of course). Whenever an implementation is added to that function name or any of its dependencies, the previously assembled typed-function is discarded, so that a new one will be constructed on its next use. + +Multiple different instances can coexist and have different collections of operations. Moreover, only the source files for the operations actually desired are ever visited in the import tree, so minimizing a bundle for a specific subset of operations should be quite straightforward. + +Hopefully the test cases, especially `test/_pocomath.mjs` and `test/custom.js`, will show off these aspects in action. + +Note that 'subtract' is implemented as a 'generic' operation, that depends only on the 'add' and 'negate' operations (and so doesn't care what types it is operating on). + +Furthermore, note that 'Complex' is implemented in a way that doesn't care about the types of the real and imaginary components, so with the 'bigint' type defined here as well, we obtain Gaussian integers for free. + +This core could be extended with many more operations, and more types could be defined, and additional sub-bundles like `number/all.mjs` or clever conditonal loaders like `complex/extendByComplex.mjs` could be defined. + +Hopefully this shows promise. It is an evolution of the concept first prototyped in [picomath](https://code.studioinfinity.org/glen/picomath). However, picomath depended on typed-function allowing mutable function entities, which turned out not to be performant. Pocomath, on the other hand, uses typed-function v3 as it stands, although it does suggest that it would be helpful to extend typed-function with subtypes, and it could even be reasonable to move the dependency tracking into typed-function itself (given that typed-function already supports self-dependencies, it would not be difficult to extend that to inter-dependencies between different typed-functions). + +Note the conception of Pocomath includes allowing one implementation to depend just on a specific signature of another function, for efficiency's sake (if for example 'bar(Matrix)' knows it will only call 'foo(Matrix)', it avoids another type-dispatch). That capability did not actually come up in this toy example, so it remains unimplemented, but it should and could easily be added. diff --git a/test/_PocomathInstance.mjs b/test/_PocomathInstance.mjs new file mode 100644 index 0000000..d48cfd8 --- /dev/null +++ b/test/_PocomathInstance.mjs @@ -0,0 +1,13 @@ +import assert from 'assert' +import PocomathInstance from '../PocomathInstance.mjs' + +describe('PocomathInstance', () => { + it('creates an instance that can define typed-functions', () => { + const pi = new PocomathInstance('dummy') + pi.install({'add': {'any,any': [[], (a,b) => a+b]}}) + assert.strictEqual(pi.add(2,2), 4) + assert.strictEqual(pi.add('Kilroy', 17), 'Kilroy17') + assert.strictEqual(pi.add(1, undefined), NaN) + assert.throws(() => pi.add(1), TypeError) + }) +})