Please sign in to comment.
Rewrite the type representation to use syntax objects
Previously, Hackett has used a prefab structure representation for its type language. User-specified type annotations would be translated into prefab structures as necessary. This was in contrast to Turnstile’s technique of using syntax objects directly to represent types, and its primary advantage has been finer control over the way types are internally structured. Turnstile, in contrast, is at the whims of the way Racket expands expressions. Unfortunately, prefab structures come at a downside: they cannot be easily converted back to syntax if that becomes necessary. Generally, this hasn’t been a problem, since usually types are written by the user, translated into the internal representation, and then only used for typechecking. There is little need to go the other way, since macros can query the state of the typechecker if necessary. Sometimes, however, it is useful to be able to insert a type produced by the typechecker into the expansion of a macro, such as when implementing things like typeclass deriving. Conceptually, a macro that derives a typeclass instance expands from this: (data (Maybe a) (Just a) Nothing) (derive-instance/Show #'Maybe) ...into this: (instance (Show a) => (Show (Maybe a)) ....) Information about the Maybe type’s constructors are not stored using the surface syntax, however; they use the fully-parsed type representation. This makes it difficult to reformulate the (Maybe a) type used as the instance head and the (Show a) constraint used in the instance context. This problem is exacerbated when trying to do fancier things, like expanding to an explicitly-typed intermediate language. This commit attempts to achieve the best of both worlds by providing a syntax-valued type representation with a similar amount of structure that was provided by the prefab structure representation. Unlike the Turnstile approach, which represents types as ordinary Racket expressions (and therefore must carefully tread around things introduced by the expander’s Racket-oriented assumptions, such as the introduction of #%app), the representation used in this commit effectively defines an entirely new type language that includes its own set of core forms, distinct from the core forms that appear in fully-expanded Racket programs. Hackett types still use the Racket macroexpander, and the full power of the Racket macro language is supported, but they must expand to the Hackett type language instead of expanding to Racket expressions. Time will tell if this type representation is superior than the old one, but initial results are promising. Racket is good at representing things to be expanded as syntax objects, and syntax/parse provides a more-than-capable language for matching on fully-expanded types. This should hopefully make it easier to reason about the operation of the typechecker, and it should make implementing new features simpler.
- Loading branch information...
Showing with 925 additions and 679 deletions.
- +65 −69 hackett-lib/hackett/private/adt.rkt
- +119 −150 hackett-lib/hackett/private/base.rkt
- +46 −72 hackett-lib/hackett/private/class.rkt
- +56 −55 hackett-lib/hackett/private/kernel.rkt
- +3 −2 hackett-lib/hackett/private/prim/op.rkt
- +13 −14 hackett-lib/hackett/private/prim/type-provide.rkt
- +3 −2 hackett-lib/hackett/private/toplevel.rkt
- +353 −0 hackett-lib/hackett/private/type-language.rkt
- +190 −297 hackett-lib/hackett/private/typecheck.rkt
- +76 −17 hackett-lib/hackett/private/util/stx.rkt
- +1 −1 hackett-test/tests/hackett/typecheck.rkt
Oops, something went wrong.