Skip to content

Haskell Template Haskell Guide — Meta-Programming and Code Generation

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about Haskell Template Haskell Guide. We cover key concepts, practical examples, and best practices to help you master this topic.

Haskell Template Haskell performs compile-time Code Generation using spliced expressions $(mkFoo ...) and quotations ( [d| data Foo = Foo |] ) -- with reify for inspecting existing declarations and TH-supported libraries like lens and aeson for deriving instances.

Basic TH

{-# LANGUAGE TemplateHaskell #-}

import Language.Haskell.TH

-- Generate a function declaration
makeIdentity :: Name -> DecsQ
makeIdentity name = do
    let body = NormalB (VarE 'id)
        clause = Clause [] body []
        funDec = FunD name [clause]
    return [funDec]

-- Use splice to generate code
$(makeIdentity 'myId)
-- Equivalent to: myId :: a -> a; myId x = x

Quotations

-- Expression quotation
expr = [| 1 + 2 |]
-- Returns Exp representing the expression

-- Declaration quotation
decls = [d|
    data Color = Red | Green | Blue
        deriving (Show, Eq)
  |]
-- Returns [Dec]

-- Type quotation
ty = [t| Maybe Int |]
-- Returns Type

-- Pattern quotation
pat = [p| Just x |]
-- Returns Pat

Reification

-- Inspect existing declarations
inspectName :: Name -> Q Info
inspectName = reify

-- Example: get constructors of a type
getConstructors :: Name -> Q [Name]
getConstructors name = do
    info <- reify name
    case info of
        TyConI (DataD _ _ _ cons _) ->
            return [conName | NormalC conName _ <- cons]
        _ -> return []

Practical Uses

{-# LANGUAGE TemplateHaskell #-}

-- Generate lenses (from lens library)
import Control.Lens
import Control.Lens.TH

data Person = Person
    { _personName :: String
    , _personAge  :: Int
    }
makeLenses ''Person  -- generates nameLens, ageLens

-- Generate JSON instances
import Data.Aeson.TH
deriveJSON defaultOptions ''Person

-- Generate enum helpers
data Weekday = Mon | Tue | Wed | Thu | Fri
deriveEnum ''Weekday

Common Mistakes

1. Stage restriction

Splices can't refer to local variables. $(f x) where x is a runtime value won't work. TH is compile-time only.

2. Template Haskell across modules

Splices in a module run before the module is compiled. The module exporting splice definitions must be compiled first.

3. Verbose error messages

TH errors can be cryptic. Use runQ in GHCi to test small TH snippets interactively.

Practice Questions

1. What is a splice in Template Haskell? $(expr) evaluates expr at compile time and inserts the resulting code into the program.

2. What is a quotation? [| ... |], [d| ... |], [t| ... |] capture Haskell code as TH data types (Exp, Dec, Type).

3. What does reify do? Looks up the compile-time information about a name (type, constructors, methods) for use in code generation.

FAQ

{{< faq question="Does Template Haskell slow down compilation?" >}} Yes, significantly. TH runs during compilation. Use it sparingly and consider alternative approaches (GHC Generics, deriving) first. {{< /faq >}}

{{< faq question="What is the Q monad?" >}} The Q monad represents the compile-time environment. It provides name generation, error reporting, and reification. {{< /faq >}}

{{< faq question="Can I generate code conditionally?" >}} Yes. TH can inspect the environment (reify), check flags, and generate different code based on compile-time conditions. {{< /faq >}}

What's Next

Now that you've completed the Haskell tutorial series, explore other languages.

Topic Description Link
Julia Start learning Julia Julia
Clojure Start learning Clojure Clojure

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro