HORIZON HASKELLDocslts/ghc-10.0.xc7d136e2026-10-12Search names, modules, packages, or :: a typeCtrl K

GHC 10.0.0.20260917 · lts/ghc-10.0.x · c7d136e · 2026-10-12

Moduleth-compat-0.1.7

Language.Haskell.TH.Syntax.Compat

  • 4 types
  • 2 classes
  • 25 values
valuebindCode :: Monad m => m a -> (a -> Code m b) -> Code m b
#

Variant of (>>=) which allows effectful computations to be injected into code generation.

valuebindCode_ :: Monad m => m a -> Code m b -> Code m b
#

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.

valuehoistCode :: Monad m => (forall x. m x -> n x) -> Code m a -> Code n a
#

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)

valuejoinCode :: Monad m => m (Code m a) -> Code m a
#

A useful combinator for embedding monadic actions into Code myCode :: ... => Code m a myCode = joinCode $ do x <- someSideEffect return (makeCodeWith x)

valueliftCode :: m (TExp a) -> Code m a
#

Lift a monadic action producing code into the typed Code representation

valueunTypeCode :: Quote m => Code m a -> m Exp
#

Extract the untyped representation from the typed representation

newtypenewtype Code (m :: Type -> Type) (a :: TYPE r)
#

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 type a, then the quotation has type Quote m => Code m a

  • typed splices inside of typed quotes, written as $$(...) where ... is an arbitrary expression of type Quote m => Code m a

Traditional expression quotes and splices let us construct ill-typed expressions:

Example2 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:

Example1 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

Instances1IsCode
  • Quote q => IsCode q a (Code q a)Defined in th-compat-0.1.7 · Language.Haskell.TH.Syntax.Compat
classclass Monad m => Quote (m :: Type -> Type) where
#

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

    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.

Instances2Quote
  • Quote QDefined in ghc-internal-10.0.0 · GHC.Internal.TH.Monad
  • Quote IODefined in ghc-internal-10.0.0 · GHC.Internal.TH.Monad