diff --git a/Item-Specifications.md b/Item-Specifications.md index 9c64f27..a538a3f 100644 --- a/Item-Specifications.md +++ b/Item-Specifications.md @@ -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: