Scoping in template haskell

Hi all, I am trying to get familiar with template haskell and I'm wondering whether the following is possible and if so, how it would be done properly... I have two templates, and I'd like to use one from the other. For instance the first one might be gen1 :: Int -> ExpQ gen1 i = [| "<<" ++ (show i) ++ ">>" |] Thus, I gould do
$(gen1 42)
and I'd get "<<42>>" now I'd like to use gen2 in another generated expression so that I could so
$(gen2 [42, 66])
and get "<<42>><<66>>" My naive intention was to write gen2 :: [Int] -> ExpQ gen2 is = [| map (\x -> $(gen1 x)) is |] which gives me "Stage error: `x' is bound at stage 2 but used at stage 1 So I guess my actual question would be: how do I pass a variable bound outside a quotation into another splice used in that quotation? Bests, Lars

First off, the first code isn't doing exactly what you think; gen1 3, for example, generates the parse tree: "<<" ++ show 3 ++ ">>" You can improve this in the following way: gen1 i = let x = "<<" ++ show i ++ ">>" in [| x |] which generates (for gen1 3, again) ['<', '<', '3', '>', '>'] Alternatively, you can generate the expression directly: gen1 i = LitE $ StringE $ "<<" ++ show i ++ ">>" which gives you exactly the parse tree "<<3>>". Now, the compiler will definitely treat the last two the same, but I'm not sure it will constant-fold "show 3" into "3" in your case. The "runQ" trick is really useful; in ghci; just use runQ with the code that you want to generate:
:set -fth :m +Language.Haskell.TH runQ [| "<<42>><<66>>" |] LitE (StringL "<<42>><<66>>")
You then just need to figure out how to make that object from the
inputs you have.
Also, here's something simple to try:
appendStrQ :: [ExpQ] -> ExpQ
appendStrQ = foldr (\x rest -> [| $(x) ++ $(rest) |]) [| "" |]
gen2 = appendStrQ . map gen1
-- ryan
On Wed, Mar 19, 2008 at 5:17 AM, Lars Oppermann
Hi all,
I am trying to get familiar with template haskell and I'm wondering whether the following is possible and if so, how it would be done properly...
I have two templates, and I'd like to use one from the other. For instance the first one might be
gen1 :: Int -> ExpQ gen1 i = [| "<<" ++ (show i) ++ ">>" |]
Thus, I gould do
$(gen1 42)
and I'd get "<<42>>"
now I'd like to use gen2 in another generated expression so that I could so
$(gen2 [42, 66])
and get "<<42>><<66>>"
My naive intention was to write
gen2 :: [Int] -> ExpQ gen2 is = [| map (\x -> $(gen1 x)) is |]
which gives me "Stage error: `x' is bound at stage 2 but used at stage 1
So I guess my actual question would be: how do I pass a variable bound outside a quotation into another splice used in that quotation?
Bests, Lars _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Wed, Mar 19, 2008 at 10:46 AM, Ryan Ingram
gen1 i = LitE $ StringE $ "<<" ++ show i ++ ">>"
Oops, two mistakes here: 1) StringE should be StringL 2) splices need to be in the Q monad. To fix (2), you can either add a "return" here, or, there are conveniently lowercase constructors for much of TH that return results in the Q monad:
gen1 i = return $ LitE $ StringL $ "<<" ++ show i ++ ">>" or gen1 i = litE $ StringL $ "<<" ++ show i ++ ">>"

Thanks for pointing me in the right direction... especially the
mentioning of lowercase constructors helped a lot. I'll clean up my
actual code (creating XML representation of record-style datatypes) a
bit and post it. Maybe you or someone else has some comments.
Bests,
Lars
On Wed, Mar 19, 2008 at 6:50 PM, Ryan Ingram
On Wed, Mar 19, 2008 at 10:46 AM, Ryan Ingram
wrote: gen1 i = LitE $ StringE $ "<<" ++ show i ++ ">>"
Oops, two mistakes here: 1) StringE should be StringL 2) splices need to be in the Q monad.
To fix (2), you can either add a "return" here, or, there are conveniently lowercase constructors for much of TH that return results in the Q monad:
gen1 i = return $ LitE $ StringL $ "<<" ++ show i ++ ">>" or gen1 i = litE $ StringL $ "<<" ++ show i ++ ">>"
participants (2)
-
Lars Oppermann
-
Ryan Ingram