I'm trying to understand how the Quasi Quoter generates TH structures. So I'm trying to convert the first example from Template Meta-programming for Haskell, from a quoted format to just the types.
gen :: [Format] -> ExpQ -> ExpQ
gen [] x = x
gen (D:xs) x = [| \n -> $(gen xs [| $x ++ show n |]) |]
gen (S:xs) x = [| \s -> $(gen xs [| $x ++ s |]) |]
gen (L s:xs) x = gen xs [| $x ++ $(THS.lift s) |]
gen (D:xs) x
would convert to
gen (D:xs) x = lamE [varP $ mkName "n"]
(appE (appE (varE 'gen) (varE 'xs))
(uInfixE (x) (varE '(Prelude.++))
(appE (varE 'Prelude.show) (varE $ mkName "n"))))
However, this fragment will not compile the reference to 'xs
.
GHC spits out the following error:
src/Print/Default.hs:28:51:
Stage error: the non-top-level quoted name 'xs
must be used at the same stage at which is is bound
In the Template Haskell quotation 'xs
In the first argument of `varE', namely 'xs
In the second argument of `appE', namely `(varE 'xs)'
Is there some other way that you need to reference the name of a function parameter for Template Haskell to be able to use it?
user2407038 is right that the translation is off. This is a more correct translation:
gen (D:xs) x = lamE [varP (mkName "n")] $
gen xs $
varE '(++)
`appE` x
`appE` (varE 'show `appE` varE (mkName "n"))
You don't reference the name of xs
or gen
here: you just recursively call the function to generate a bit more AST. That keeps everything in the same stage.