Formerly, when a self-reference like `self(Tuple<number>)` was encountered,
but the `Tuple<number>` instance of a `Tuple<T>` implementation for this
operation had not yet been instantiated, the reference would be fulfilled
with a call to the catchall implementation for `Tuple`. Now the
necessary instance is instantiated on the spot and referred to instead.
This change is used to complete return-type specification for all of the
Tuple functions.
Typed-function's sort order/matching algorithm was interfering with
template resolution. This commit solves the difficulty by moving the
"catchall" implementations that implement generation of new template
instances into a separate "fallback" typed-function universe, so that
Pocomath can control exactly when that is searched.
Removes a couple of the matching anomalies already noted in the tests.
Also extends return types to somewhat more functions.
These changes greatly increased the need for precision in generating
implementations for signatures of operations whenever possible. So this
commit also includes a refactor that basically caches all of the
conversions of Pocomath implementations to typed-function implementatios so
that they are more often externally available (i.e., not disrupted so much
after invalidation).
Also changed the notation for an upper bound template to the more
readable 'T:number' (instead of 'T (= number', which was supposed to
look like the non-strict subset relation).
This feature helps specify the return type of implementations where
the return type depends on the exact subtype that the implementation
was called with, such as negate.
With this commit, there's a rudimentary function that attaches return-type
information, so it can be supplied, and PocomathInstance then proceeds
to check for it everywhere necessary (and supply it in all the internal
operations it builds). But so far in all of those place where it's checked
for, it's just ignored.
I think the next step will be just to put the return type info as a property
on the function itself. That should actually ease all of the code.
Inspired by https://github.com/josdejong/mathjs/discussions/2212 and
https://github.com/josdejong/mathjs/issues/2585.
Provides a simple adapter function `adapted` which takes a class
implementing an arithmetical datatype and returns a PocomathInstance
with a new type for that class, invoking the methods of the class
in a standard way for the Pocomath/mathjs operations. (That instance
can then be installed in another to add the new type to any instance
you like, including the default one.)
Uses this facility to bring fraction.js Fraction into Pocomath, and
tests the resulting type.
Currently the "standard" interface for an arithmetical type is heavily modeled
after the design of fraction.js, but with experience with other 3rd-party types
it could be streamlined to something pretty generic (and the Fraction
adaptation could be patched to conform to the resulting "standard"). Or a
proposal along the lines of https://github.com/josdejong/mathjs/discussions/2212
could be adopted, and a shim could be added to fraction.js to conform to
**that** standard.
Resolves#30.
Even in the setup just prior to this commit, a quaternion with entries
of type `number` is simply a `Complex<Complex<number>>`
So if we provide a convenience wrapper to create sucha thing, we
instantly have a quaternion data type. All of the operations come for
"free" if they were properly defined for the `Complex` template.
Multiplication already was, `abs` needed a little tweak, but there is
absolutely no "extra" code to support quaternions. (This commit
does not go through and check all arithmetic functions for proper operation
and tweak those that still need some generalization.)
Note that with the recursive template instantiation, a limit had to be placed
on template instantiation depth. The limit moves deeper as actual arguments
that are deeper nested instantiations are seen, so as long as one doesn't
immediately invoke a triply-nested template, for example, the limit will
never prevent an actual computation. It just prevents a runaway in the types
that Pocomath thinks it needs to know about. (Basically before, using the
quaternion creator would produce `Complex<Complex<number>>`. Then when you
called it again, Pocomath would think "Maybe I will need
`Complex<Complex<Complex<number>>>`?!" and create that, even though it had
never seen that, and then another level next time, and so on. The limit
just stops this progression one level beyond any nesting depth that's
actually been observed.
This means that the real and imaginary parts of a Complex must now be
the same type. This seems like a real benefit: a Complex with a number real
part and a bigint imaginary part does not seem sensible.
Note that this is now straining typed-function in (at least) the following
ways:
(1) In this change, it was necessary to remove the logic that the square root
of a negative number calls complex square root, which then calls back
to the number square root in its algorithm. (This was creating a circular
reference in the typed-function which the old implementation of Complex
was somehow sidestepping.)
(2) typed-function could not follow conversions that would be allowed by
uninstantiated templates (e.g. number => Complex<number> if the latter
template has not been instantiated) and so the facility for
instantiating a template was surfaced (and for example is called explicitly
in the demo loader `extendToComplex`. Similarly, this necessitated
making the unary signature of the `complex` conversion function explicit,
rather than just via implicit conversion to Complex.
(3) I find the order of implementations is mattering more in typed-function
definitions, implying that typed-function's sorting algorithm is having
trouble distinguishing alternatives.
But otherwise, the conversion went quite smoothly and I think is a good demo
of the power of this approach. And I expect that it will work even more
smoothly if some of the underlying facilities (subtypes, template types) are
integrated into typed-function.
Includes a full implementation of a type-homogeneous Tuple type, using the template types
feature, as a demonstration/check of its operation.
Co-authored-by: Glen Whitney <glen@studioinfinity.org>
Reviewed-on: #45
Also adds a `mean()` operation so there will be at least one operation
that takes only a rest parameter, to exercise the ban on splitting
such a parameter between the stored value and new arguments.
Adds various tests of chains.
Resolves#32.
Relational functions are added using templates, and existing generic functions are made more strict with them. Also a new built-in typeOf function is added, that automatically updates itself.
Resolves#34.
Co-authored-by: Glen Whitney <glen@studioinfinity.org>
Reviewed-on: #41
This should eventually be moved into typed-function itself, but for
now it can be implemented on top of the existing typed-function.
Uses subtypes to define (and error-check) gcd and lcm, which are only
defined for integer arguments.
Resolves#36.
Merging of Pocomath modules is eased by allowing one PocomathInstance to
be merged into another. That allows types, for example, to be exported
as a PocomathInstance (so there is no need for a special identifier
convention for types; they can be directly added with an installType
method). Also, larger modules can just be exported as an instance, since
there is more flexibility and more checking in merging PocomathInstances
than raw modules.
This allows types to be collected; prior to this commit they
were conflicting from different modules.
Uses this fix to extend sqrt to bigint, with the convention
that it is undefined for non-perfect squares when 'predictable'
is false and is the "best" approximation to the square root when
'predictable' is true. Furthermore, for negative bigints, you might
get a Gaussian integer when predictable is false; or you will just get
your argument back when 'predictable' is true because what other
bigint could you give back for a negative bigint?
Also had to modify tests on the sign in sqrt(Complex) and add functions
'zero' and 'one' to get types to match, as expected in #27.
Adds numerous tests.
Resolves#26.
Resolves#27.
Also implements a config object that upon change, lazily invalidates
all operations that access it.
Also allows references to signatures with nonexistent types (which
typed-function does not); they come back as undefined.
Uses these features to implement sqrt for number and complex.
Resolves#7.
Allows dependencies to be economically expressed and used.
For example, see the new definition of subtract.
Credit for the basic idea goes to James Drew, see
https://stackoverflow.com/a/41525264Resolves#21.