Question

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?

Was it helpful?

Solution

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.

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