0

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?

  • 1
    That conversion is not correct. Notice that in the first version, locally bound names which are quoted are also spliced back in. So if `x` is locally bound, you can't have `$x`, but you can have `[| ... $x ... |]`. In the 2nd version, you haven't done this, and it doens't make sense to do this, since `lamE [varP ..]` expects a `ExpQ` but the `\n ->` inside of the splice expects a `String`. – user2407038 Jun 02 '14 at 20:18

1 Answers1

1

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.

aavogt
  • 1,308
  • 6
  • 14