Update Item Specifications

Glen Whitney 2025-04-01 23:27:22 +00:00
parent ffe5d5b587
commit 915572c971

@ -2,9 +2,9 @@ This page is devoted to concepts and designs for the structure of items in the T
## Map-like object indexed by identifier and types
In this concept, we think of the TypeDispatcher object `math` simply as a big map indexed by a string identifier and a list of types, with a handful of special properties:
In this concept, we think of the TypeDispatcher object `math` simply as a big map indexed by a string identifier and a list of types. Since those are complex non-string indices, which JavaScript doesn't really handle gracefully, we provide the basic indexing method `math.resolve('foo', [T1, T2, ..., Tn])`, with a handful of special properties:
* The `math` object is set up so that you can write `math.foo(a, b, c)` to call `math['foo', [typeOf(a), typeOf(b), typeOf(c)]](a, b, c)`.
* The `math` object is set up so that you can write `math.foo(a, b, c)` rather than `math.resolve('foo', [math.typeOf(a), math.typeOf(b), math.typeOf(c)])(a, b, c)`. For values that are functions, we should also be able to write `math.foo.resolve(T1, T2, T3)`.
* The stored entities are "dependent objects" -- they record at their creation time what other entries of the TypeDispatcher object they depend on, and if any of those change, they are regenerated as needed.
* The keys and values of the `math` object can be specified in a pattern-matching style that supports/simulates generic functions
@ -33,7 +33,7 @@ export const square = (math, [T]) => {
This seems a trifle "heavy" but I'm not seeing clear ways at the moment to streamline it.
Note the above implementation of square works for all types, so there is not any type matching going on in the definition. So let's take a look at what we would have to do for the `multiply` implementation on two numbers -- a plain function with no dependencies. Something like
Note the above implementation of square works for all types, so there is not any type matching going on in the definition. (Presumably this creates a fallback universal implementation, and you could still add specialized implementations, say on a Boolean argument.) So let's take a look at what we would have to do for the `multiply` implementation on two numbers -- a plain function with no dependencies. Something like
```
export const multiply = [[Number, Number], Returns(Number, (a, b) => a * b)]
```
@ -51,7 +51,7 @@ export const add = [[Complex, Complex]], (math, [T, U]) => {
)
}]
```
Note that the Complex types in the signature specification are not "ground" types -- they are generic types, and so serve as patterns that say that this export specifies the value for any two-entry signature in which each entry is an instance of complex. We then get the actual call types `T` and `U` in the factory function -- they could conceivably be `Complex(BigInt)` and `Complex(Number)`. Any two complex types will be fine, so long as we can add their base types, which we will discover when we try to fetch the `add` implementation on those two types.
Note that the Complex types in the signature specification are not "ground" types -- they are generic types, and so serve as patterns that say that this export specifies the value for any two-entry signature in which each entry is an instance of complex. We then get the actual call types `T` and `U` in the factory function -- they could conceivably be `Complex(BigInt)` and `Complex(Number)`, say. Any two complex types will be fine, so long as we can add their base types, which we will discover when we try to fetch the `add` implementation on those two types.
Putting a few features together, consider `sqrt` of a number, which produces different implementations depending on what types are available and the configuration: