Question

Quasi-quotes allow generating AST code during compilations, but it inserts generated code at the place where Quasi-quote was written. Is it possible in any way to insert the compile-time generated code elsewhere? For example in specific module files which are different from the one where QQ was written? It would depend on hard-coded module structure, but that's fine.

If that's not possible with QQ but anyone knows a different way of achieving it, I am open for suggestions.

Was it helpful?

Solution

To answer this, it's helpful to know what a quasi-quoter is. From the GHC Documentation, a quasi-quoter is a value of

data QuasiQuoter = QuasiQuoter { quoteExp  :: String -> Q Exp,
                                 quotePat  :: String -> Q Pat,
                                 quoteType :: String -> Q Type,
                                 quoteDec  :: String -> Q [Dec] }

That is, it's a parser from an arbitrary String to one or more of ExpQ, PatQ, TypeQ, and DecQ, which are Template Haskell representations of expressions, patterns, types, and declarations respectively.

When you use a quasi-quote, GHC applies the parser to the String to create a ExpQ (or other type), then splices in the resulting template haskell expression to produce an actual value.

It sounds like what you're asking to do is separate the quasiquote parsing and splicing, so that you have access to the TH expression. Then you can import that expression into another module and splice it there yourself.

Knowing the type of a quasi-quoter, it's readily apparent this is possible. Normally you use a QQ as

-- file Expr.hs
eval :: Expr -> Integer
expr = QuasiQuoter { quoteExp = parseExprExp, quotePat =  parseExprPat }

-- file Foo.hs
import Expr
myInt = eval [expr|1 + 2|]

Instead, you can extract the parser yourself, get a TH expression, and splice it later:

-- file Foo.hs
import Expr

-- run the QQ parser
myInt_TH :: ExpQ
myInt_TH = quoteExp expr "1 + 2"

-- file Bar.hs
import Foo.hs

-- run the TH splice
myInt = $(myInt_TH)

Of course if you're writing all this yourself, you can skip the quasi-quotes and use a parser and Template Haskell directly. It's pretty much the same thing either way.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top