Here is one way that is rather fragile, but it seems to work. While you can not refer to? x in Exp, which uses the haskell pattern, you can refer to the definition in another module, for example:
reserved_prefix_x = ?x
Below is the code that generates such variables as described above in one ghc run, and in the second ghc run the variables actually refer to implicit parameters.
{-# LANGUAGE TemplateHaskell, NoMonomorphismRestriction #-} module GenMod (h) where import Data.Generics import Data.IORef import Data.List import Language.Haskell.Meta.Parse as P import Language.Haskell.TH import Language.Haskell.TH.Quote import Language.Haskell.TH.Syntax import qualified Data.Set as S import qualified Language.Haskell.Exts.QQ as Q import System.IO.Unsafe h = Q.hs { quoteExp = \s -> do r <- either fail (upVars . return) (P.parseExp s) writeMod' return r } pfx = "q_" {-# NOINLINE vars #-} vars :: IORef (S.Set String) vars = unsafePerformIO (newIORef S.empty) writeMod' = runIO $ writeFile "GEN.hs" . ppMod =<< readIORef vars writeMod = -- might be needed to avoid multiple calls to writeFile? -- in this example this is called for every use of `h' QuasiQuoter { quoteDec = \ _ -> do writeMod' [d| _ = () |] } ppMod xs = "{-# LANGUAGE NoMonomorphismRestriction, ImplicitParams #-}\n\ \module GEN where\n" ++ unlines (map (\x -> pfx ++ x ++ " = ?" ++ x) (S.toList xs)) upVars x = do x' <- x runIO $ modifyIORef vars (S.union (getMatchingVars x')) runIO $ print =<< readIORef vars return x' getMatchingVars = everything S.union (mkQ S.empty (\ (OccName x) -> maybe S.empty S.singleton (stripPrefix pfx x)))
Main.hs file, which uses the quasiquater GenMod.hs:
{-# LANGUAGE NoMonomorphismRestriction, ImplicitParams, QuasiQuotes, TemplateHaskell, CPP #-} import GenMod #ifndef stage1 import GEN #endif f_ = [h| q_hithere |]
You need to call ghc twice, for example:
ghci -Dstage1 Main.hs GHCi, version 7.6.1: http://www.haskell.org/ghc/ :? for help [1 of 2] Compiling GenMod ( GenMod.hs, interpreted ) [2 of 2] Compiling Main ( Ex.hs, interpreted ) fromList ["hithere"] Ex.hs:8:6: Not in scope: `q_hithere' Failed, modules loaded: GenMod.
Although ghc fails, it still generates GEN.hs, which contains:
{-
What will be there when you load Main (leaving the -D flag)
*Main> :t f_ f_ :: (?hithere::t) => t
Such a problem is probably not worth it. Perhaps other situations calling other programs from TH are more motivated, for example, built-in calls to other languages http://hpaste.org/50837 (gfortran example)
Since I used the default haskell-src-meta parser, the quasi-quarter gets the use of the variables "reserved_prefix_x" not "? X". It should be possible to accept "? X" without too much difficulty.