feat(Tuple): Stub for a template type
This adds the target initial definition of a homogeneous Tuple<T> type, and just enough processing that the type can be defined and non-template methods that deal with the generic base type Tuple can be called. Still has no actual template instantiation.
This commit is contained in:
parent
21ce098f98
commit
27bf23db54
9 changed files with 176 additions and 3 deletions
82
src/tuple/Types/Tuple.mjs
Normal file
82
src/tuple/Types/Tuple.mjs
Normal file
|
@ -0,0 +1,82 @@
|
|||
/* A template type representing a homeogeneous tuple of elements */
|
||||
import PocomathInstance from '../../core/PocomathInstance.mjs'
|
||||
|
||||
const Tuple = new PocomathInstance('Tuple')
|
||||
// First a base type that will generally not be used directly
|
||||
Tuple.installType('Tuple', {
|
||||
test: t => t && typeof t === 'object' && 'elts' in t && Array.isArray(t.elts)
|
||||
})
|
||||
// Now the template type that is the primary use of this
|
||||
Tuple.installType('Tuple<T>', {
|
||||
// For now we will assume that any 'Type<T>' refines 'Type', so this is
|
||||
// not necessary:
|
||||
// refines: 'Tuple',
|
||||
// But we need there to be a way to determine the type of a tuple:
|
||||
infer: ({typeOf, joinTypes}) => t => {
|
||||
return joinTypes(t.elts.map(typeOf))
|
||||
},
|
||||
// For the test, we can assume that t is already a base tuple,
|
||||
// and we get the test for T as an input and we have to return
|
||||
// the test for Tuple<T>
|
||||
test: testT => t => t.elts.every(testT),
|
||||
// These are only invoked for types U such that there is already
|
||||
// a conversion from U to T, and that conversion is passed as an input
|
||||
// and we have to return the conversion to Tuple<T>:
|
||||
from: {
|
||||
'Tuple<U>': convert => tu => ({elts: tu.elts.map(convert)}),
|
||||
// Here since there is no U it's a straight conversion:
|
||||
T: t => ({elts: [u]}), // singleton promotion
|
||||
// Whereas the following will let you go directly from an element
|
||||
// convertible to T to a singleton Tuple<T>. Not sure if we really
|
||||
// want that, but we'll try it just for kicks.
|
||||
U: convert => u => ({elts: [convert(u)]})
|
||||
}
|
||||
})
|
||||
|
||||
Tuple.promoteUnary = {
|
||||
'Tuple<T>': ({'self(T)': me}) => t => ({elts: t.elts.map(me)})
|
||||
}
|
||||
|
||||
Tuple.promoteBinaryUnary = {
|
||||
'Tuple<T>,Tuple<T>': ({'self(T,T)': meB, 'self(T)': meU}) => (s,t) => {
|
||||
let i = -1
|
||||
let result = []
|
||||
while (true) {
|
||||
i += 1
|
||||
if (i < s.elts.length) {
|
||||
if (i < t.elts.length) result.append(meB(s.elts[i], t.elts[i]))
|
||||
else results.append(meU(s.elts[i]))
|
||||
continue
|
||||
}
|
||||
if (i < t.elts.length) result.append(meU(t.elts[i]))
|
||||
else break
|
||||
}
|
||||
return {elts: result}
|
||||
}
|
||||
}
|
||||
|
||||
Tuple.promoteBinary = {
|
||||
'Tuple<T>,Tuple<T>': ({'self(T,T)': meB}) => (s,t) => {
|
||||
const lim = Math.max(s.elts.length, t.elts.length)
|
||||
const result = []
|
||||
for (let i = 0; i < lim; ++i) {
|
||||
result.append(meB(s.elts[i], t.elts[i]))
|
||||
}
|
||||
return {elts: result}
|
||||
}
|
||||
}
|
||||
|
||||
Tuple.promoteBinaryStrict = {
|
||||
'Tuple<T>,Tuple<T>': ({'self(T,T)': meB}) => (s,t) => {
|
||||
if (s.elts.length !== t.elts.length) {
|
||||
throw new RangeError('Tuple length mismatch') // get name of self ??
|
||||
}
|
||||
const result = []
|
||||
for (let i = 0; i < s.elts.length; ++i) {
|
||||
result.append(meB(s.elts[i], t.elts[i]))
|
||||
}
|
||||
return {elts: result}
|
||||
}
|
||||
}
|
||||
|
||||
export {Tuple}
|
14
src/tuple/equal.mjs
Normal file
14
src/tuple/equal.mjs
Normal file
|
@ -0,0 +1,14 @@
|
|||
export * from './Types/Tuple.mjs'
|
||||
|
||||
export const equal = {
|
||||
// Change this to a template implementation (or maybe add template
|
||||
// implementation to handle matching types, and have mixed template-base
|
||||
// method returning false to catch test of two tuples of different types.
|
||||
'Tuple,Tuple': ({self, length}) => (s,t) => {
|
||||
if (length(s) !== length(t)) return false
|
||||
for (let i = 0; i < length(s); ++i) {
|
||||
if (!self(s.elts[i], t.elts[i])) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
6
src/tuple/isZero.mjs
Normal file
6
src/tuple/isZero.mjs
Normal file
|
@ -0,0 +1,6 @@
|
|||
export {Tuple} from './Types/Tuple.mjs'
|
||||
|
||||
export const isZero = {
|
||||
'Tuple<T>': ({'self(T)': me}) => t => t.elts.every(isZero)
|
||||
}
|
||||
|
3
src/tuple/length.mjs
Normal file
3
src/tuple/length.mjs
Normal file
|
@ -0,0 +1,3 @@
|
|||
export {Tuple} from './Types/Tuple.mjs'
|
||||
|
||||
export const length = {Tuple: () => t => t.elts.length}
|
20
src/tuple/native.mjs
Normal file
20
src/tuple/native.mjs
Normal file
|
@ -0,0 +1,20 @@
|
|||
import {Tuple} from './Types/Tuple.mjs'
|
||||
|
||||
export const add = Tuple.promoteBinaryUnary
|
||||
export const complex = Tuple.promoteBinaryStrict
|
||||
export const conjugate = Tuple.promoteUnary
|
||||
// May want to replace equal with compare based on lexicographic ordering?
|
||||
export {equal} from './equal.mjs'
|
||||
export const invert = Tuple.promoteUnary
|
||||
export {isZero} from './isZero.mjs'
|
||||
export {length} from './length.mjs'
|
||||
export const multiply = Tuple.promoteBinaryUnary
|
||||
export const negate = Tuple.promoteUnary
|
||||
export const one = Tuple.promoteUnary
|
||||
export const quotient = Tuple.promoteBinaryStrict
|
||||
export const roundquotient = Tuple.promoteBinaryStrict
|
||||
export const sqrt = Tuple.promoteUnary
|
||||
export {tuple} from './tuple.mjs'
|
||||
export const zero = Tuple.promoteUnary
|
||||
|
||||
export {Tuple}
|
6
src/tuple/tuple.mjs
Normal file
6
src/tuple/tuple.mjs
Normal file
|
@ -0,0 +1,6 @@
|
|||
export {Tuple} from './Types/Tuple.mjs'
|
||||
|
||||
/* The purpose of the template argument is to ensure that all of the args
|
||||
* are convertible to the same type.
|
||||
*/
|
||||
export const tuple = {'...any': () => args => ({elts: args})}
|
Loading…
Add table
Add a link
Reference in a new issue