2025-04-15 01:17:27 -07:00
|
|
|
## Nanomath core
|
|
|
|
|
|
|
|
The organization here is to keep the core engine as compact and as agnostic
|
|
|
|
as to what sort of functions and types there might be in a TypeDispatcher as
|
|
|
|
possible. This division will keep it plausible to break out just the core
|
|
|
|
as a TypeDispatcher package that could be used independently for any collection
|
|
|
|
of overloaded functions on a universe of types. So we want to place as few
|
|
|
|
assumptions/preconditions as to what functions and/or types there will be.
|
|
|
|
|
|
|
|
## Core Types
|
|
|
|
|
|
|
|
As of this writing, the only two types required to be in a TypeDispatcher are
|
|
|
|
Undefined (the type inhabited only by `undefined`) and TypeOfTypes (the type
|
|
|
|
inhabited exactly by Type objects).
|
|
|
|
|
feat: more utility functions
Adds type constants zero and one, and allows you to obtain them
directly from a type object. This facility creates a behavior
with a parametric type: the type of `math.zero(T)` where `T` is a
Type object (i.e., has type `TypeOfTypes`) depends not just on that
type TypeOfTypes, but instead on the _value_ of the argument `T`. Since
nanomath is not (yet?) equipped to handle typing such a method, we just
set its return type to a new constant NotAType that (hopefully) does not
work with the rest of the type system. Also allows you to compute `zero`
and `one` from an example value, rather than from the type object itself.
Adds utility function `isZero` to test if a value is zero.
As usual so far, the additions uncovered some remaining bugs, which
this PR fixes. For example, there was a problem in that resolution of
the `one` method was failing because the `Any` pattern was blocking
matching of the `TypeOfTypes` pattern. Although we may eventually need to
sort the patterns for a given method to maintain a reasonable matching
order, for now the solution was just to move the two patterns into the
same source file and explicitly order them. (With the way onType and
Implementations are currently implemented, the proper ordering is more
general to more specific, i.e. later implementations supersede earlier
ones.
Adds many new tests, as always.
2025-04-15 16:23:55 -07:00
|
|
|
There is also a constant NotAType which is the type-world analogue of NaN for
|
|
|
|
numbers. It is occasionally used for the rare behavior that truly does not
|
|
|
|
return any particular type, such as the method `zero` that takes a Type and
|
|
|
|
returns its zero element. However, it does not really work as a Type, and in
|
|
|
|
particular, do _not_ merge it into any TypeDispatcher -- it will disrupt the
|
|
|
|
type and method resolution process.
|
|
|
|
|
2025-04-15 01:17:27 -07:00
|
|
|
## Core methods
|
|
|
|
|
|
|
|
Similarly, as of this writing the only methods that must be in a TypeDispatcher
|
|
|
|
are:
|
|
|
|
|
|
|
|
Type
|
|
|
|
: the class (constructor) for Type objects, called via `new Type(...)`.
|
|
|
|
Note that merely constructing a Type does not regeister it within any
|
|
|
|
TypeDispatcher; it must be `.merge()`d into the TypeDispatcher.
|
|
|
|
|
|
|
|
typeOf
|
|
|
|
: determines the type of any value
|
|
|
|
|
|
|
|
merge
|
|
|
|
: adds values and methods to the TypeDispatcher
|
|
|
|
|
|
|
|
resolve
|
|
|
|
: finds values and methods in the TypeDispatcher, by key and types list
|
|
|
|
|
|
|
|
Any (other) functions an instance wants to have acting on the core Types
|
|
|
|
should be defined elsewhere and merged into the instance.
|
|
|
|
|
|
|
|
In nanomath as a whole, rather than within its core, we also assume that
|
|
|
|
the NumberT type of regular JavaScript numbers is always present (i.e., no
|
|
|
|
need to check if it is in the instance), and we put all functions that we
|
|
|
|
want to define on the core Types in the coretypes directory.
|