TemplateHaskell


References:


Q, the quotation monad, seems to be the main thing.

General:

(E: Expresssion, P: Pattern, L: Literal?, T: type?)

ExpQ is an alias for Q Exp

Example use:

Clash.Prelude Language.Haskell.TH> runQ [| \x -> 1 |]
LamE [VarP x_0] (LitE (IntegerL 1))

Clash.Prelude Language.Haskell.TH> :t it
it :: Language.Haskell.TH.Exp
Prelude> :set -XTemplateHaskell
Prelude> import Language.Haskell.TH.Syntax
Prelude Language.Haskell.TH.Syntax>

Quoting with quotes

Non-type values can be quoted with one single quote:

Prelude Language.Haskell.TH.Syntax> :t 'id
'id :: Name

Prelude Language.Haskell.TH.Syntax> 'id
GHC.Base.id

Prelude Language.Haskell.TH.Syntax> :t id
id :: a -> a

Type values can be quoted with two single quotes:

Prelude Language.Haskell.TH.Syntax> ''Bool
GHC.Types.Bool

Prelude Language.Haskell.TH.Syntax> :t ''Bool
''Bool :: Name

Prelude Language.Haskell.TH.Syntax> 'Bool
<interactive>:31:1: error:
    • Not in scope: data constructor ‘Bool’
    • In the Template Haskell quotation 'Bool

Builtins

Prelude Language.Haskell.TH.Syntax> :t LamE
LamE :: [Pat] -> Exp -> Exp

Prelude Language.Haskell.TH.Syntax> :t VarP
VarP :: Name -> Pat

The TemplateHaskell extension got to enable for some stuff to work:

Prelude Language.Haskell.TH.Syntax> runQ [e| Just x |]
<interactive>:20:18: error: parse error on input ‘]’

Prelude Language.Haskell.TH.Syntax> :set -XTemplateHaskell
Prelude Language.Haskell.TH.Syntax> runQ [e| Just x |]
AppE (ConE GHC.Maybe.Just) (UnboundVarE x)

Stage restriction

varname is used in a top-level splice, quasi-quote, or annotation,
        and must be imported, not defined locally

From https://well-typed.com/blog/2020/06/th-for-static-data/:

However if we define isStaticIdSet and the Lift instance in the same module, GHC can’t call liftTyped as it’s not yet compiled by the time we need it.

Conventions

Last letter of variable names usually follow this convention:

Info

Some Syntax

From https://markkarpov.com/tutorial/th.html:

Declaration [d ] Q [Dec]
Expression [e ] Q Exp
Typed expression [
Type [t ] Q Type
Pattern [p ] Q Pat

Some types

https://hackage.haskell.org/package/template-haskell-2.23.0.0/docs/Language-Haskell-TH.html

Misc

λ> import Language.Haskell.TH
λ> a = mkName "hi"
λ> :t a
a :: Name
ghci> :t reify ''Bool
reify ''Bool :: Q Info

-- https://github.com/seanwestfall/templatehaskell
ghci> $(stringE . show =<< reify ''Bool)
"TyConI
(DataD
  []
  GHC.Types.Bool
  []
  Nothing
  [NormalC GHC.Types.False [],
   NormalC GHC.Types.True []]
  [])"
ghci> :t DataD [] (mkName "Foo") [] Nothing
DataD [] (mkName "Foo") [] Nothing :: [Con] -> [DerivClause] -> Dec

ghci> [d| data Foo = Foo Int |]
[DataD [] Foo_1 [] Nothing [NormalC Foo_2 [(Bang NoSourceUnpackedness NoSourceStrictness,ConT GHC.Types.Int)]] []]

ghci> [d| data Itype = C0 | C1 |]
[DataD [] Itype_3 [] Nothing [NormalC C0_4 [],NormalC C1_5 []] []]

ghci> [d| data Itype = C0 | C1 | C2 |]
[DataD [] Itype_6 [] Nothing [NormalC C0_7 [],NormalC C1_8 [],NormalC C2_9 []] []]

ghci> normalC (mkName "C0") []
NormalC C0 []

ghci> dataD (pure []) (mkName "Itype") [] Nothing [] []
DataD [] Itype [] Nothing [] []