Skip to content

Consider desugaring TemplateHaskell Quotes between Tc and HsToCore

Motivation

GHC currently dedicates 3000 lines to desugaring type-checked quotes directly to CoreExprs building the quoted AST using wired-in identifiers in Language.Haskell.TH.Lib (in GHC.HsToCore.Quote).

For example, looking at repLiteral, the general style seems to be to (1) turn an Int literal into an Integer, (2) desugar this literal to Core, (3) generate Core that calls the wired-in integerL. Wow, this is complicated!

Proposal

I read the companion paper to Oleg Kiselyov's OCaml 2023 workshop talk. There he describes a translation scheme for (typed, but untyped should work as well) quotes in terms of simple, wired-in combinator functions such as mkLam :: Quote m => String -> (m Exp -> m Exp) -> m Exp and lift :: Quote m => a -> m Exp.

Following this work, I think it would be worthwhile to desugar the following user-written eta function as follows:

eta :: Quote m => (m Exp -> m Exp) -> m Exp
eta f = [| \x -> $(f [| x |]) |] 
==>
eta f = mkLam "x" (\(x :: m Exp) -> f x)

where mkLam is defined in TH.Lib (or perhaps at some hidden, internal place of our choosing) and defined as

mkLam :: Quote m => String -> (m Exp -> m Exp) -> m Exp
mkLam s f = do n <- newName s; lam (varP n) (f (varE n))

And a literal, variable, etc. quote would desugar using lift:

q = [| 42 |]
===>
q = lift (42 :: Integer)

Small caveat: This would require us to infer the type of the literal, but perhaps we can just default.

The idea is to move as much glue code from HsToCore.Quote into non-exposed, perhaps inlined combinators inside ghc-internal.

Edited by Sebastian Graf
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information