The Q :: * -> *
type constructor defined in Language.Haskell.TH.Syntax
is an abstract type representing computations which have access to the compile-time environment of the module in which the computation is run. The Q
type also handles variable substituion, called name capture by TH (and discussed here.) All splices have type Q X
for some X
.
The compile-time environment includes:
The Q
type also has the ability to generate fresh names, with the function newName :: String -> Q Name
. Note that the name is not bound anywhere implicitly, so the user must bind it themselves, and so making sure the resulting use of the name is well-scoped is the responsibility of the user.
Q
has instances for Functor,Monad,Applicative
and this is the main interface for manipulating Q
values, along with the combinators provided in Language.Haskell.TH.Lib
, which define a helper function for every constructor of the TH ast of the form:
LitE :: Lit -> Exp
litE :: Lit -> ExpQ
AppE :: Exp -> Exp -> Exp
appE :: ExpQ -> ExpQ -> ExpQ
Note that ExpQ
, TypeQ
, DecsQ
and PatQ
are synonyms for the AST types which are typically stored inside the Q
type.
The TH library provides a function runQ :: Quasi m => Q a -> m a
, and there is an instance Quasi IO
, so it would seem that the Q
type is just a fancy IO
. However, the use of runQ :: Q a -> IO a
produces an IO
action which does not have access to any compile-time environment - this is only available in the actual Q
type. Such IO
actions will fail at runtime if trying to access said environment.