There are a few things around "properties" I'd like to have in Typer which are similar yet different. If any of you has ideas about how to conflate/merge some of them, or how to clearly distinguish them or what to do about them, I'd like to hear it:
Some properties I'm thinking of would be: - docstrings (as annotations on functions, types, and other variables): These could be properties of *values*, or properties of *bindings*. For types and functions, properties of values would probably work well (tho it prevents giving different docstrings to different names of the same function), but for variables holding things like integers, associating the docstring to the integer is not going to work well, so we probably need to support properties of bindings (we can probably limit them to actual declarations (i.e. let-bindings) since docstrings of function arguments are probably not needed). - decision procedures: These are the "macros" associated with a given type to automatically find/construct an expression of that type, as needed for implicit arguments. This is what we need to implement type classes. These can be associated to *values* or the *bindings*. In general I'd prefer using values than bindings since its natural/normal to manipulate values whereas it's unusual to manipulate bindings. Also, I'd like to have those properties be lexically scoped, so I can locally add a decision procedure for a type and elsewhere add another decision procedure for that same type. - declaration macros: normal macros (invoked using the function call syntax) are special values of type Macro, but there are other macros to use in other syntactic contexts, such as declaration macros (i.e. macros that can be invoked in the <decls> part of "let <decls> in <exp>"). Currently, declaration macros are shared with normal macros, i.e. it's one and the same namespace so if you define a `foo` macro it will apply to invocations of `foo` in <exp> as in <decls>. I'd like to separate those two cases. Especially because there will inevitably be more cases (e.g. lvalue macros, case-pattern macros, ...). These could be implemented as properties of bindings. But that means that if I rebind the `or` function, I end up also affecting the `or` pattern macro. So maybe another way to solve this would be to provided different namespaces. So I can independently define the `foo` var, the `foo` pattern-macro, the `foo` lvalue-macro, the `foo` declaration macro etc... without interference. A cheap way to do that is to use some name-prefixing scheme, so the `foo` pattern-macro is kept in the `patternmacro_foo` variable. I kind of like this name-prefixing solution, but I'm not sure what the convention should look like (which magic character to use). Also, better would be to have the "namespace prefix" be an object rather than a string.
Hmm... so reading what I wrote, maybe what I need/want is to extend the `senv`, which is the part of the elaboration environment used to find the deBruijn index of a variable. IOW currently it's a Map from strings (variable identifiers) to (reverse) deBruijn indices, and the above suggests I should maybe extend this map such that it can be indexed by arbitrary objects (e.g. a pair of a namespace-object and a string).
This said, currently those `senv` are environments specific to the elaboration phase, they tend to be transient, so we'd probably want to promote them somehow.
Related to this: how should the above interact with modules (which are basically tuples with names fields)? How can a module indicate what is the docstring/decision-procedure/declaration-macro corresponding to a particular field?
Stefan