On Oct 14, 2021, at 11:59 AM, Benjamin Redelings <benjamin.redelings@gmail.com> wrote:
I asked about this on Haskell-Cafe, and was recommended to ask here instead. Any help is much appreciated!
* The PolyKinds paper was the most helpful thing I've found, but it doesn't cover type classes. I'm also not sure that all implementers can follow algorithm descriptions that are laid out as inference rules, but maybe that could be fixed with a few hints about how to run the rules in reverse. Also, in practice I think an implementer would want to follow GHC in specifying the initial kind of a data type as k1 -> k2 -> ... kn -> *.
2. The following question (which I have maybe kind of answered now, but could use more advice on) is an example of what I am hoping such documentation would explain:
Q: How do you handle type variables that are present in class methods, but are not type class parameters? If there are multiple types/classes in a single recursive group, the kind of such type variables might not be fully resolved until a later type-or-class is processed. Is there a recommended approach?
I can see two ways to proceed:
i) First determine the kinds of all the data types, classes, and type synonyms. Then perform a second pass over each type or class to determine the kinds of type variables (in class methods) that are not type class parameters.
Further investigation revealed that GHC takes yet another approach (I think):
ii) Alternatively, record the kind of each type variable as it is encountered -- even though such kinds may contain unification kind variables. After visiting all types-or-classes in the recursive group, replace any kind variables with their definition, or with a * if there is no definition.
I've currently implement approach i), which requires doing kind inference on class methods twice.
iii) Represent kinds with modifiable variables. Substitution can be implemented by modifying kind variables in-place. This is (I think) called "zonking" in the GHC sources.
This solves a small mystery for me, since I previously thought that zonking was just replacing remaining kind variables with '*'. And indeed this seems to be an example of zonking, but not what zonking is (I think).
Zonking looks painful to implement, but approach (i) might require multiple passes over types to update the kind of type variables, which might be worse...