feat: add Vector generic type
This commit is contained in:
parent
0765ba7202
commit
cc4d77f128
4 changed files with 85 additions and 4 deletions
|
@ -1,8 +1,9 @@
|
|||
import * as booleans from './boolean/all.js'
|
||||
import * as coretypes from './coretypes/all.js'
|
||||
import * as booleans from './boolean/all.js'
|
||||
import * as complex from './complex/all.js'
|
||||
import * as generics from './generic/all.js'
|
||||
import * as numbers from './number/all.js'
|
||||
import * as complex from './complex/all.js'
|
||||
import * as vectors from './vector/all.js'
|
||||
import {TypeDispatcher} from '#core/TypeDispatcher.js'
|
||||
|
||||
// At the moment, since we are not sorting patterns in any way,
|
||||
|
@ -12,9 +13,10 @@ import {TypeDispatcher} from '#core/TypeDispatcher.js'
|
|||
// whatever has been merged before.)
|
||||
// Hence, in building the math instance, we put generics first because
|
||||
// they should only kick in when there are not specific implementations,
|
||||
// and complex next becausewe want its conversion (which converts _any_
|
||||
// and complex next because we want its conversion (which converts _any_
|
||||
// non-complex type to complex, potentially making a poor overload choice)
|
||||
// to be tried last.
|
||||
const math = new TypeDispatcher(generics, complex, booleans, coretypes, numbers)
|
||||
const math = new TypeDispatcher(
|
||||
generics, complex, vectors, booleans, coretypes, numbers)
|
||||
|
||||
export default math
|
||||
|
|
43
src/vector/Vector.js
Normal file
43
src/vector/Vector.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
import {NotAType, Type} from '#core/Type.js'
|
||||
|
||||
const isVector = v => Array.isArray(v)
|
||||
|
||||
export const Vector = new Type(isVector, {
|
||||
specialize(CompType) {
|
||||
const compTest = CompType.test
|
||||
const specTest = v => isVector(v) && v.every(compTest)
|
||||
const typeName = `Vector(${CompType})`
|
||||
if (CompType.concrete) {
|
||||
const typeOptions = {typeName}
|
||||
if ('zero' in CompType) typeOptions.zero = [CompType.zero]
|
||||
const vectorCompType = new Type(specTest, typeOptions)
|
||||
vectorCompType.Component = CompType
|
||||
vectorCompType.vector = true
|
||||
return vectorCompType
|
||||
}
|
||||
// Wrapping a generic type in Vector
|
||||
return new Type(specTest, {
|
||||
typeName,
|
||||
specialize: (...args) => this.specialize(CompType.specialize(...args)),
|
||||
specializesTo: VT => this.specializesTo(VT)
|
||||
&& CompType.specializesTo(VT.Component),
|
||||
refine: (v, typer) => {
|
||||
const eltTypes = v.map(elt => CompType.refine(elt, typer))
|
||||
const newCompType = eltTypes[0]
|
||||
if (eltTypes.some(T => T !== newCompType)) {
|
||||
throw new TypeError(
|
||||
`can't refine ${typeName} to ${v}; `
|
||||
+ `not all entries have type ${newCompType}`)
|
||||
}
|
||||
return this.specialize(newCompType)
|
||||
}
|
||||
})
|
||||
},
|
||||
specializesTo: VT => VT.vector,
|
||||
refine(v, typer) {
|
||||
const eltTypes = v.map(elt => typer(elt))
|
||||
let compType = eltTypes[0]
|
||||
if (eltTypes.some(T => T !== compType)) compType = NotAType
|
||||
return this.specialize(compType)
|
||||
}
|
||||
})
|
35
src/vector/__test__/Vector.spec.js
Normal file
35
src/vector/__test__/Vector.spec.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
import assert from 'assert'
|
||||
import {Vector} from '../Vector.js'
|
||||
import {NotAType} from '#core/Type.js'
|
||||
import math from '#nanomath'
|
||||
|
||||
describe('Vector Type', () => {
|
||||
it('correctly recognizes vectors', () => {
|
||||
assert(Vector.test([3, 4]))
|
||||
assert(!Vector.test({re: 3, im: 4}))
|
||||
})
|
||||
it('can fully type vectors', () => {
|
||||
const {BooleanT, Complex, NumberT} = math.types
|
||||
const typ = math.typeOf
|
||||
const cplx = math.complex
|
||||
assert.strictEqual(typ([3, 4]), Vector(NumberT))
|
||||
assert.strictEqual(typ([true, false]), Vector(BooleanT))
|
||||
assert.strictEqual(typ([3, false]), Vector(NotAType))
|
||||
assert.strictEqual(typ([cplx(3, 4), cplx(5)]), Vector(Complex(NumberT)))
|
||||
assert.strictEqual(typ([[3, 4], [5]]), Vector(Vector(NumberT)))
|
||||
})
|
||||
it('can refine when nested', () => {
|
||||
const {Complex, NumberT} = math.types
|
||||
const cplx = math.complex
|
||||
const VecComplex = Vector(Complex)
|
||||
const vcEx = [cplx(3, 4), cplx(5)]
|
||||
assert(VecComplex.test(vcEx))
|
||||
const vcType = VecComplex.refine(vcEx, math.typeOf)
|
||||
assert.strictEqual(vcType, Vector(Complex(NumberT)))
|
||||
const CplxVec = Complex(Vector)
|
||||
const cvEx = cplx([3,4], [5, 0])
|
||||
assert(CplxVec.test(cvEx))
|
||||
const cvType = CplxVec.refine(cvEx, math.typeOf)
|
||||
assert.strictEqual(cvType, Complex(Vector(NumberT)))
|
||||
})
|
||||
})
|
1
src/vector/all.js
Normal file
1
src/vector/all.js
Normal file
|
@ -0,0 +1 @@
|
|||
export * as typeDefinition from './Vector.js'
|
Loading…
Add table
Add a link
Reference in a new issue