feat: Add and illustrate multiple ways of specifying implementations #19

Merged
glen merged 3 commits from pocomath_notation into main 2022-07-23 05:06:49 +00:00
2 changed files with 34 additions and 5 deletions
Showing only changes of commit 0002a55bcb - Show all commits

View File

@ -16,6 +16,10 @@ Furthermore, note that 'Complex' is implemented in a way that doesn't care about
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 conditional loaders like `complex/extendToComplex.mjs` could be defined.
Also see the comments for the public member functions of
`core/PocomathInstance.mjs` for further details on the structure and API of this
scheme for organizing a CAS.
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.

View File

@ -28,15 +28,16 @@ export default class PocomathInstance {
* @param {Object<string, Object<Signature, [string[], function]>>} ops
* The only parameter ops gives the semantics of the operations to install.
* The keys are operation names. The value for a key is an object
* mapping (typed-function) signature strings to pairs of dependency
* lists and implementation functions.
* mapping (typed-function) signature strings to specifications of
* of dependency lists and implementation functions.
*
* A dependency list is a list of strings. Each string can either be the
* name of a function that the corresponding implementation has to call,
* or a specification of a particular signature of a function that it has
* to call, in the form 'FN(SIGNATURE)'. Note the function name can be
* the special value 'self' to indicate a recursive call to the given
* operation (either with or without a particular signature.
* to call, in the form 'FN(SIGNATURE)' [not implemented yet].
* Note the function name can be the special value 'self' to indicate a
* recursive call to the given operation (either with or without a
* particular signature.
*
* There are two cases for the implementation function. If the dependency
* list is empty, it should be a function taking the arguments specified
@ -45,6 +46,30 @@ export default class PocomathInstance {
* requested functions as values, to a function taking the arguments
* specified by the signature and returning the value.
*
* There are various specifications currently allowed for the
* dependency list and implementation function:
*
* 1) Just a function. Then the dependency list is assumed to be empty.
*
* 2) A pair (= Array with two entries) of a dependency list and the
* implementation function.
*
* 3) An object whose property named 'does' gives the implementation
* function and whose property named 'uses', if present, gives the
* dependency list (which is assumed to be empty if the property is
* not present).
*
* 4) A call to the 'use' function exported from the this module, with
* first argument the dependencies and second argument the
* implementation.
*
* For a visual comparison of the options, this proof-of-concept uses
* option (1) when possible for the 'number' type, (3) for the 'Complex'
* type, (4) for the 'bigint' type, and (2) under any other circumstances.
* Likely a fleshed-out version of this scheme would settle on just one
* or two of these options or variants thereof, rather than providing so
* many different ones.
*
* Note that the "operation" named `Types` is special: it gives
* types that must be installed in the instance. In this case, the keys
* are type names, and the values are objects with a property 'test'