refactor: Convert resolution to two-tier system

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.
This commit is contained in:
Glen Whitney 2022-08-29 09:30:07 -04:00
parent a2f76a55b8
commit de42c22ab4
13 changed files with 428 additions and 278 deletions

View file

@ -46,6 +46,9 @@ describe('The default full pocomath instance "math"', () => {
assert.strictEqual(math.returnTypeOf('identity', 'Fraction'), 'Fraction')
assert.strictEqual(
math.returnTypeOf('quotient', 'bigint,bigint'), 'bigint')
math.abs(math.complex(2,1)) //TODO: ditto
assert.strictEqual(
math.returnTypeOf('abs','Complex<NumInt>'), 'number')
})
it('can subtract numbers', () => {

View file

@ -39,8 +39,8 @@ describe('complex', () => {
})
it('checks for equality', () => {
assert.ok(math.equal(math.complex(3,0), 3))
assert.ok(math.equal(math.complex(3,2), math.complex(3, 2)))
assert.ok(math.equal(math.complex(3, 0), 3))
assert.ok(math.equal(math.complex(3, 2), math.complex(3, 2)))
assert.ok(!(math.equal(math.complex(45n, 3n), math.complex(45n, -3n))))
assert.ok(!(math.equal(math.complex(45n, 3n), 45n)))
})

View file

@ -135,13 +135,8 @@ describe('A custom instance', () => {
assert.strictEqual(
inst.typeMerge(3, inst.complex(4.5,2.1)),
'Merge to Complex<number>')
// The following is the current behavior, since 3 converts to 3+0i
// which is technically the same Complex type as 3n+0ni.
// This should clear up when Complex is templatized
assert.strictEqual(inst.typeMerge(3, inst.complex(3n)), 'Merge to Complex')
// But types that truly cannot be merged should throw a TypeError
// Should add a variation of this with a more usual type once there is
// one not interconvertible with others...
assert.throws(
() => inst.typeMerge(3, inst.complex(3n)), TypeError)
inst.install(genericSubtract)
assert.throws(() => inst.typeMerge(3, undefined), TypeError)
})

View file

@ -8,14 +8,12 @@ describe('tuple', () => {
it('does not allow unification by converting consecutive arguments', () => {
assert.throws(() => math.tuple(3, 5.2, 2n), /TypeError.*unif/)
// Hence, the order matters in a slightly unfortunate way,
// but I think being a little ragged in these edge cases is OK:
assert.throws(
() => math.tuple(3, 2n, math.complex(5.2)),
/TypeError.*unif/)
assert.deepStrictEqual(
math.tuple(3, math.complex(2n), 5.2),
{elts: [math.complex(3), math.complex(2n), math.complex(5.2)]})
assert.throws(
() => math.tuple(3, math.complex(2n), 5.2),
/TypeError.*unif/)
})
it('can be tested for zero and equality', () => {