Safe Haskell | Trustworthy |
---|---|
Language | Haskell2010 |
GHC.Internal.TH.Monad
Description
This module is used internally in GHC's integration with Template Haskell and defines the Monads of Template Haskell, and associated definitions.
This is not a part of the public API, and as such, there are no API guarantees for this module from version to version.
Import Language.Haskell.TH or Language.Haskell.TH.Syntax instead!
Synopsis
- addCorePlugin :: String -> Q ()
- addDependentDirectory :: FilePath -> Q ()
- addDependentFile :: FilePath -> Q ()
- addForeignFilePath :: ForeignSrcLang -> FilePath -> Q ()
- addForeignSource :: ForeignSrcLang -> String -> Q ()
- addModFinalizer :: Q () -> Q ()
- addTempFile :: String -> Q FilePath
- addTopDecls :: [Dec] -> Q ()
- badIO :: String -> IO a
- bindCode :: Monad m => m a -> (a -> Code m b) -> Code m b
- bindCode_ :: Monad m => m a -> Code m b -> Code m b
- counter :: IORef Uniq
- extsEnabled :: Q [Extension]
- getDoc :: DocLoc -> Q (Maybe String)
- getPackageRoot :: Q FilePath
- getQ :: Typeable a => Q (Maybe a)
- hoistCode :: Monad m => (forall x. m x -> n x) -> Code m a -> Code n a
- isExtEnabled :: Extension -> Q Bool
- isInstance :: Name -> [Type] -> Q Bool
- joinCode :: Monad m => m (Code m a) -> Code m a
- liftCode :: forall a m. m (TExp a) -> Code m a
- location :: Q Loc
- lookupName :: Bool -> String -> Q (Maybe Name)
- lookupTypeName :: String -> Q (Maybe Name)
- lookupValueName :: String -> Q (Maybe Name)
- newDeclarationGroup :: Q [Dec]
- newNameIO :: String -> IO Name
- putDoc :: DocLoc -> String -> Q ()
- putQ :: Typeable a => a -> Q ()
- recover :: Q a -> Q a -> Q a
- reify :: Name -> Q Info
- reifyAnnotations :: Data a => AnnLookup -> Q [a]
- reifyConStrictness :: Name -> Q [DecidedStrictness]
- reifyFixity :: Name -> Q (Maybe Fixity)
- reifyInstances :: Name -> [Type] -> Q [InstanceDec]
- reifyModule :: Module -> Q ModuleInfo
- reifyRoles :: Name -> Q [Role]
- reifyType :: Name -> Q Type
- report :: Bool -> String -> Q ()
- reportError :: String -> Q ()
- reportWarning :: String -> Q ()
- runIO :: IO a -> Q a
- runQ :: Quasi m => Q a -> m a
- sequenceQ :: Monad m => forall a. [m a] -> m [a]
- unTypeCode :: forall a m. Quote m => Code m a -> m Exp
- unTypeQ :: forall a m. Quote m => m (TExp a) -> m Exp
- unsafeCodeCoerce :: forall a m. Quote m => m Exp -> Code m a
- unsafeTExpCoerce :: forall a m. Quote m => m Exp -> m (TExp a)
- newtype Code (m :: Type -> Type) (a :: TYPE r) = Code {
- examineCode :: m (TExp a)
- newtype Q a = Q {}
- class (MonadIO m, MonadFail m) => Quasi (m :: Type -> Type) where
- qNewName :: String -> m Name
- qReport :: Bool -> String -> m ()
- qRecover :: m a -> m a -> m a
- qLookupName :: Bool -> String -> m (Maybe Name)
- qReify :: Name -> m Info
- qReifyFixity :: Name -> m (Maybe Fixity)
- qReifyType :: Name -> m Type
- qReifyInstances :: Name -> [Type] -> m [Dec]
- qReifyRoles :: Name -> m [Role]
- qReifyAnnotations :: Data a => AnnLookup -> m [a]
- qReifyModule :: Module -> m ModuleInfo
- qReifyConStrictness :: Name -> m [DecidedStrictness]
- qLocation :: m Loc
- qRunIO :: IO a -> m a
- qGetPackageRoot :: m FilePath
- qAddDependentFile :: FilePath -> m ()
- qAddDependentDirectory :: FilePath -> m ()
- qAddTempFile :: String -> m FilePath
- qAddTopDecls :: [Dec] -> m ()
- qAddForeignFilePath :: ForeignSrcLang -> String -> m ()
- qAddModFinalizer :: Q () -> m ()
- qAddCorePlugin :: String -> m ()
- qGetQ :: Typeable a => m (Maybe a)
- qPutQ :: Typeable a => a -> m ()
- qIsExtEnabled :: Extension -> m Bool
- qExtsEnabled :: m [Extension]
- qPutDoc :: DocLoc -> String -> m ()
- qGetDoc :: DocLoc -> m (Maybe String)
- class Monad m => Quote (m :: Type -> Type) where
- newtype TExp (a :: TYPE r) = TExp {}
Documentation
addCorePlugin :: String -> Q () Source #
Adds a core plugin to the compilation pipeline.
addCorePlugin m
has almost the same effect as passing -fplugin=m
to ghc
in the command line. The major difference is that the plugin module m
must not belong to the current package. When TH executes, it is too late
to tell the compiler that we needed to compile first a plugin module in the
current package.
addDependentDirectory :: FilePath -> Q () Source #
Record external directories that runIO is using (dependent upon). The compiler can then recognize that it should re-compile the Haskell file when a directory changes.
Notes:
- ghc -M does not know about these dependencies - it does not execute TH.
- The dependency is shallow, based only on the direct content. Basically, it only sees a list of names. It does not look at directory metadata, recurse into subdirectories, or look at file contents. As long as the list of names remains the same, the directory is considered unchanged.
- The state of the directory is read at the interface generation time, not at the time of the function call.
addDependentFile :: FilePath -> Q () Source #
Record external files that runIO is using (dependent upon). The compiler can then recognize that it should re-compile the Haskell file when an external file changes.
Expects an absolute file path.
Notes:
- ghc -M does not know about these dependencies - it does not execute TH.
- The dependency is based on file content, not a modification time
addForeignFilePath :: ForeignSrcLang -> FilePath -> Q () Source #
Same as addForeignSource
, but expects to receive a path pointing to the
foreign file instead of a String
of its contents. Consider using this in
conjunction with addTempFile
.
This is a good alternative to addForeignSource
when you are trying to
directly link in an object file.
addForeignSource :: ForeignSrcLang -> String -> Q () Source #
Emit a foreign file which will be compiled and linked to the object for the current module. Currently only languages that can be compiled with the C compiler are supported, and the flags passed as part of -optc will be also applied to the C compiler invocation that will compile them.
Note that for non-C languages (for example C++) extern C
directives
must be used to get symbols that we can access from Haskell.
To get better errors, it is recommended to use #line pragmas when emitting C files, e.g.
{-# LANGUAGE CPP #-} ... addForeignSource LangC $ unlines [ "#line " ++ show (862 + 1) ++ " " ++ show "libraries/ghc-internal/src/GHC/Internal/TH/Monad.hs" , ... ]
addModFinalizer :: Q () -> Q () Source #
Add a finalizer that will run in the Q monad after the current module has been type checked. This only makes sense when run within a top-level splice.
The finalizer is given the local type environment at the splice point. Thus
reify
is able to find the local definitions when executed inside the
finalizer.
addTempFile :: String -> Q FilePath Source #
Obtain a temporary file path with the given suffix. The compiler will delete this file after compilation.
addTopDecls :: [Dec] -> Q () Source #
Add additional top-level declarations. The added declarations will be type checked along with the current declaration group.
bindCode :: Monad m => m a -> (a -> Code m b) -> Code m b Source #
Variant of (>>=)
which allows effectful computations to be injected
into code generation.
bindCode_ :: Monad m => m a -> Code m b -> Code m b Source #
Variant of (>>)
which allows effectful computations to be injected
into code generation.
extsEnabled :: Q [Extension] Source #
List all enabled language extensions.
getDoc :: DocLoc -> Q (Maybe String) Source #
Retrieves the Haddock documentation at the specified location, if one
exists.
It can be used to read documentation on things defined outside of the current
module, provided that those modules were compiled with the -haddock
flag.
getPackageRoot :: Q FilePath Source #
Get the package root for the current package which is being compiled. This can be set explicitly with the -package-root flag but is normally just the current working directory.
The motivation for this flag is to provide a principled means to remove the assumption from splices that they will be executed in the directory where the cabal file resides. Projects such as haskell-language-server can't and don't change directory when compiling files but instead set the -package-root flag appropriately.
getQ :: Typeable a => Q (Maybe a) Source #
Get state from the Q
monad. Note that the state is local to the
Haskell module in which the Template Haskell expression is executed.
hoistCode :: Monad m => (forall x. m x -> n x) -> Code m a -> Code n a Source #
Modify the ambient monad used during code generation. For example, you
can use hoistCode
to handle a state effect:
handleState :: Code (StateT Int Q) a -> Code Q a
handleState = hoistCode (flip runState 0)
isExtEnabled :: Extension -> Q Bool Source #
Determine whether the given language extension is enabled in the Q
monad.
isInstance :: Name -> [Type] -> Q Bool Source #
Is the list of instances returned by reifyInstances
nonempty?
If you're confused by an instance not being visible despite being
defined in the same module and above the splice in question, see the
docs for newDeclarationGroup
for a possible explanation.
joinCode :: Monad m => m (Code m a) -> Code m a Source #
A useful combinator for embedding monadic actions into Code
myCode :: ... => Code m a
myCode = joinCode $ do
x <- someSideEffect
return (makeCodeWith x)
liftCode :: forall a m. m (TExp a) -> Code m a Source #
Lift a monadic action producing code into the typed Code
representation
lookupTypeName :: String -> Q (Maybe Name) Source #
Look up the given name in the (type namespace of the) current splice's scope. See Language.Haskell.TH.Syntax for more details.
lookupValueName :: String -> Q (Maybe Name) Source #
Look up the given name in the (value namespace of the) current splice's scope. See Language.Haskell.TH.Syntax for more details.
newDeclarationGroup :: Q [Dec] Source #
Template Haskell is capable of reifying information about types and terms defined in previous declaration groups. Top-level declaration splices break up declaration groups.
For an example, consider this code block. We define a datatype X
and
then try to call reify
on the datatype.
module Check where data X = X deriving Eq $(do info <- reify ''X runIO $ print info )
This code fails to compile, noting that X
is not available for reification at the site of reify
. We can fix this by creating a new declaration group using an empty top-level splice:
data X = X deriving Eq $(pure []) $(do info <- reify ''X runIO $ print info )
We provide newDeclarationGroup
as a means of documenting this behavior
and providing a name for the pattern.
Since top level splices infer the presence of the $( ... )
brackets, we can also write:
data X = X deriving Eq newDeclarationGroup $(do info <- reify ''X runIO $ print info )
putDoc :: DocLoc -> String -> Q () Source #
Add Haddock documentation to the specified location. This will overwrite
any documentation at the location if it already exists. This will reify the
specified name, so it must be in scope when you call it. If you want to add
documentation to something that you are currently splicing, you can use
addModFinalizer
e.g.
do let nm = mkName "x" addModFinalizer $ putDoc (DeclDoc nm) "Hello" [d| $(varP nm) = 42 |]
The helper functions withDecDoc
and withDecsDoc
will do this for you, as
will the funD_doc
and other _doc
combinators.
You most likely want to have the -haddock
flag turned on when using this.
Adding documentation to anything outside of the current module will cause an
error.
putQ :: Typeable a => a -> Q () Source #
Replace the state in the Q
monad. Note that the state is local to the
Haskell module in which the Template Haskell expression is executed.
Recover from errors raised by reportError
or fail
.
reify :: Name -> Q Info Source #
reify
looks up information about the Name
. It will fail with
a compile error if the Name
is not visible. A Name
is visible if it is
imported or defined in a prior top-level declaration group. See the
documentation for newDeclarationGroup
for more details.
It is sometimes useful to construct the argument name using lookupTypeName
or lookupValueName
to ensure that we are reifying from the right namespace. For instance, in this context:
data D = D
which D
does reify (mkName "D")
return information about? (Answer: D
-the-type, but don't rely on it.)
To ensure we get information about D
-the-value, use lookupValueName
:
do Just nm <- lookupValueName "D" reify nm
and to get information about D
-the-type, use lookupTypeName
.
reifyAnnotations :: Data a => AnnLookup -> Q [a] Source #
reifyAnnotations target
returns the list of annotations
associated with target
. Only the annotations that are
appropriately typed is returned. So if you have Int
and String
annotations for the same target, you have to call this function twice.
reifyConStrictness :: Name -> Q [DecidedStrictness] Source #
reifyConStrictness nm
looks up the strictness information for the fields
of the constructor with the name nm
. Note that the strictness information
that reifyConStrictness
returns may not correspond to what is written in
the source code. For example, in the following data declaration:
data Pair a = Pair a a
reifyConStrictness
would return [
under most
circumstances, but it would return DecidedLazy
, DecidedLazy][
if the
DecidedStrict
, DecidedStrict]-XStrictData
language extension was enabled.
reifyFixity :: Name -> Q (Maybe Fixity) Source #
reifyFixity nm
attempts to find a fixity declaration for nm
. For
example, if the function foo
has the fixity declaration infixr 7 foo
, then
reifyFixity 'foo
would return
. If the function
Just
(Fixity
7 InfixR
)bar
does not have a fixity declaration, then reifyFixity 'bar
returns
Nothing
, so you may assume bar
has defaultFixity
.
reifyInstances :: Name -> [Type] -> Q [InstanceDec] Source #
reifyInstances nm tys
returns a list of all visible instances (see below for "visible")
of nm tys
. That is,
if nm
is the name of a type class, then all instances of this class at the types tys
are returned. Alternatively, if nm
is the name of a data family or type family,
all instances of this family at the types tys
are returned.
Note that this is a "shallow" test; the declarations returned merely have
instance heads which unify with nm tys
, they need not actually be satisfiable.
reifyInstances ''Eq [
contains theTupleT
2 `AppT
`ConT
''A `AppT
`ConT
''B ]instance (Eq a, Eq b) => Eq (a, b)
regardless of whetherA
andB
themselves implementEq
reifyInstances ''Show [
produces every available instance ofVarT
(mkName
"a") ]Show
There is one edge case: reifyInstances ''Typeable tys
currently always
produces an empty list (no matter what tys
are given).
In principle, the *visible* instances are
* all instances defined in a prior top-level declaration group
(see docs on newDeclarationGroup
), or
* all instances defined in any module transitively imported by the
module being compiled
However, actually searching all modules transitively below the one being
compiled is unreasonably expensive, so reifyInstances
will report only the
instance for modules that GHC has had some cause to visit during this
compilation. This is a shortcoming: reifyInstances
might fail to report
instances for a type that is otherwise unusued, or instances defined in a
different component. You can work around this shortcoming by explicitly importing the modules
whose instances you want to be visible. GHC issue #20529
has some discussion around this.
reifyModule :: Module -> Q ModuleInfo Source #
reifyModule mod
looks up information about module mod
. To
look up the current module, call this function with the return
value of thisModule
.
reifyRoles :: Name -> Q [Role] Source #
reifyRoles nm
returns the list of roles associated with the parameters
(both visible and invisible) of
the tycon nm
. Fails if nm
cannot be found or is not a tycon.
The returned list should never contain InferR
.
An invisible parameter to a tycon is often a kind parameter. For example, if we have
type Proxy :: forall k. k -> Type data Proxy a = MkProxy
and reifyRoles Proxy
, we will get [
. The NominalR
, PhantomR
]NominalR
is
the role of the invisible k
parameter. Kind parameters are always nominal.
reifyType :: Name -> Q Type Source #
reifyType nm
attempts to find the type or kind of nm
. For example,
reifyType 'not
returns Bool -> Bool
, and
reifyType ''Bool
returns Type
.
This works even if there's no explicit signature and the type or kind is inferred.
report :: Bool -> String -> Q () Source #
Deprecated: Use reportError or reportWarning instead
Report an error (True) or warning (False),
but carry on; use fail
to stop.
reportError :: String -> Q () Source #
Report an error to the user, but allow the current splice's computation to carry on. To abort the computation, use fail
.
reportWarning :: String -> Q () Source #
Report a warning to the user, and carry on.
The runIO
function lets you run an I/O computation in the Q
monad.
Take care: you are guaranteed the ordering of calls to runIO
within
a single Q
computation, but not about the order in which splices are run.
Note: for various murky reasons, stdout and stderr handles are not necessarily flushed when the compiler finishes running, so you should flush them yourself.
runQ :: Quasi m => Q a -> m a Source #
"Runs" the Q
monad. Normal users of Template Haskell
should not need this function, as the splice brackets $( ... )
are the usual way of running a Q
computation.
This function is primarily used in GHC internals, and for debugging
splices by running them in IO
.
Note that many functions in Q
, such as reify
and other compiler
queries, are not supported when running Q
in IO
; these operations
simply fail at runtime. Indeed, the only operations guaranteed to succeed
are newName
, runIO
, reportError
and reportWarning
.
unTypeCode :: forall a m. Quote m => Code m a -> m Exp Source #
Extract the untyped representation from the typed representation
unTypeQ :: forall a m. Quote m => m (TExp a) -> m Exp Source #
Discard the type annotation and produce a plain Template Haskell expression
Representation-polymorphic since template-haskell-2.16.0.0.
unsafeCodeCoerce :: forall a m. Quote m => m Exp -> Code m a Source #
Unsafely convert an untyped code representation into a typed code representation.
unsafeTExpCoerce :: forall a m. Quote m => m Exp -> m (TExp a) Source #
Annotate the Template Haskell expression with a type
This is unsafe because GHC cannot check for you that the expression really does have the type you claim it has.
Representation-polymorphic since template-haskell-2.16.0.0.
newtype Code (m :: Type -> Type) (a :: TYPE r) Source #
Represents an expression which has type a
, built in monadic context m
. Built on top of TExp
, typed
expressions allow for type-safe splicing via:
- typed quotes, written as
[|| ... ||]
where...
is an expression; if that expression has typea
, then the quotation has typeQuote m => Code m a
- typed splices inside of typed quotes, written as
$$(...)
where...
is an arbitrary expression of typeQuote m => Code m a
Traditional expression quotes and splices let us construct ill-typed expressions:
>>>
fmap ppr $ runQ (unTypeCode [| True == $( [| "foo" |] ) |])
GHC.Internal.Types.True GHC.Internal.Classes.== "foo">>>
GHC.Internal.Types.True GHC.Internal.Classes.== "foo"
<interactive> error: • Couldn't match expected type ‘Bool’ with actual type ‘[Char]’ • In the second argument of ‘(==)’, namely ‘"foo"’ In the expression: True == "foo" In an equation for ‘it’: it = True == "foo"
With typed expressions, the type error occurs when constructing the Template Haskell expression:
>>>
fmap ppr $ runQ (unTypeCode [|| True == $$( [|| "foo" ||] ) ||])
<interactive> error: • Couldn't match type ‘[Char]’ with ‘Bool’ Expected type: Code Q Bool Actual type: Code Q [Char] • In the Template Haskell quotation [|| "foo" ||] In the expression: [|| "foo" ||] In the Template Haskell splice $$([|| "foo" ||])
Constructors
Code | |
Fields
|
In short, Q
provides the Quasi
operations in one neat monad for the
user.
The longer story, is that Q
wraps an arbitrary Quasi
-able monad.
The perceptive reader notices that Quasi
has only two instances, Q
itself and IO
, neither of which have concrete implementations.Q
plays
the trick of dependency
inversion,
providing an abstract interface for the user which is later concretely
fufilled by an concrete Quasi
instance, internal to GHC.
Instances
class (MonadIO m, MonadFail m) => Quasi (m :: Type -> Type) where Source #
Minimal complete definition
qNewName, qReport, qRecover, qLookupName, qReify, qReifyFixity, qReifyType, qReifyInstances, qReifyRoles, qReifyAnnotations, qReifyModule, qReifyConStrictness, qLocation, qGetPackageRoot, qAddDependentFile, qAddDependentDirectory, qAddTempFile, qAddTopDecls, qAddForeignFilePath, qAddModFinalizer, qAddCorePlugin, qGetQ, qPutQ, qIsExtEnabled, qExtsEnabled, qPutDoc, qGetDoc
Methods
qNewName :: String -> m Name Source #
Fresh names. See newName
.
qReport :: Bool -> String -> m () Source #
Arguments
:: m a | the error handler |
-> m a | action which may fail |
-> m a | Recover from the monadic |
See recover
.
qLookupName :: Bool -> String -> m (Maybe Name) Source #
True = type namespace, False = value namespace. See lookupName
.
qReify :: Name -> m Info Source #
See reify
.
qReifyFixity :: Name -> m (Maybe Fixity) Source #
See reifyFixity
.
qReifyType :: Name -> m Type Source #
See reifyType
.
qReifyInstances :: Name -> [Type] -> m [Dec] Source #
Is (n tys) an instance? Returns list of matching instance Decs (with
empty sub-Decs) Works for classes and type functions. See reifyInstances
.
qReifyRoles :: Name -> m [Role] Source #
See reifyRoles
.
qReifyAnnotations :: Data a => AnnLookup -> m [a] Source #
See reifyAnnotations
.
qReifyModule :: Module -> m ModuleInfo Source #
See reifyModule
.
qReifyConStrictness :: Name -> m [DecidedStrictness] Source #
See reifyConStrictness
.
See location
.
qRunIO :: IO a -> m a Source #
Input/output (dangerous). See runIO
.
qGetPackageRoot :: m FilePath Source #
See getPackageRoot
.
qAddDependentFile :: FilePath -> m () Source #
See addDependentFile
.
qAddDependentDirectory :: FilePath -> m () Source #
qAddTempFile :: String -> m FilePath Source #
See addTempFile
.
qAddTopDecls :: [Dec] -> m () Source #
See addTopDecls
.
qAddForeignFilePath :: ForeignSrcLang -> String -> m () Source #
See addForeignFilePath
.
qAddModFinalizer :: Q () -> m () Source #
See addModFinalizer
.
qAddCorePlugin :: String -> m () Source #
See addCorePlugin
.
qGetQ :: Typeable a => m (Maybe a) Source #
See getQ
.
qPutQ :: Typeable a => a -> m () Source #
See putQ
.
qIsExtEnabled :: Extension -> m Bool Source #
See isExtEnabled
.
qExtsEnabled :: m [Extension] Source #
See extsEnabled
.
qPutDoc :: DocLoc -> String -> m () Source #
See putDoc
.
qGetDoc :: DocLoc -> m (Maybe String) Source #
See getDoc
.
Instances
class Monad m => Quote (m :: Type -> Type) where Source #
The Quote
class implements the minimal interface which is necessary for
desugaring quotations.
- The
Monad m
superclass is needed to stitch together the different AST fragments. newName
is used when desugaring binding structures such as lambdas to generate fresh names.
Therefore the type of an untyped quotation in GHC is `Quote m => m Exp`
For many years the type of a quotation was fixed to be `Q Exp` but by
more precisely specifying the minimal interface it enables the Exp
to
be extracted purely from the quotation without interacting with Q
.
Methods
newName :: String -> m Name Source #
Generate a fresh name, which cannot be captured.
For example, this:
f = $(do nm1 <- newName "x" let nm2 =mkName
"x" return (LamE
[VarP
nm1] (LamE [VarP nm2] (VarE
nm1))) )
will produce the splice
f = \x0 -> \x -> x0
In particular, the occurrence VarE nm1
refers to the binding VarP nm1
,
and is not captured by the binding VarP nm2
.
Although names generated by newName
cannot be captured, they can
capture other names. For example, this:
g = $(do nm1 <- newName "x" let nm2 = mkName "x" return (LamE [VarP nm2] (LamE [VarP nm1] (VarE nm2))) )
will produce the splice
g = \x -> \x0 -> x0
since the occurrence VarE nm2
is captured by the innermost binding
of x
, namely VarP nm1
.