Variant of (>>=) which allows effectful computations to be injected
into code generation.
Moduleth-compat-0.1.7
Language.Haskell.TH.Syntax.Compat
- 4 types
- 2 classes
- 25 values
- Packageth-compat-0.1.7
- Exports31
- LicenceBSD-3-Clause
- SourceMonad.hs
Variant of (>>) which allows effectful computations to be injected
into code generation.
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.
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)
A useful combinator for embedding monadic actions into Code
myCode :: ... => Code m a
myCode = joinCode $ do
x <- someSideEffect
return (makeCodeWith x)
Lift a monadic action producing code into the typed Code representation
Extract the untyped representation from the typed representation
Unsafely convert an untyped code representation into a typed code representation.
The input is a filepath, which if relative is offset by the package root.
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 atyped 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
CodeexamineCode :: m (TExp a)Underlying monadic value
The Quote class implements the minimal interface which is necessary for desugaring quotations.
The
Monad msuperclass 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 NameGenerate 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 -> x0In particular, the occurrence
VarE nm1refers to the bindingVarP nm1, and is not captured by the bindingVarP nm2.Although names generated by
newNamecannot 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 -> x0since the occurrence
VarE nm2is captured by the innermost binding ofx, namelyVarP nm1.