Template Haskell allows you to do compile-time meta-programming in Haskell. The background the main technical innovations are discussed in "Template Meta-programming for Haskell", in Proc Haskell Workshop 2002.
The first example from that paper is set out below as a worked example to help get you started.
The documentation here describes the realisation in GHC. (It's rather sketchy just now; Tim Sheard is going to expand it.)
Template Haskell has the following new syntactic constructions. You need to use the flag -fglasgow-exts to switch these syntactic extensions on.
A splice is written $x, where x is an identifier, or $(...), where the "..." is an arbitrary expression. There must be no space between the "$" and the identifier or parenthesis. This use of "$" overrides its meaning as an infix operator, just as "M.x" overrides the meaning of "." as an infix operator. If you want the infix operator, put spaces around it.
A splice can occur in place of
an expression; the spliced expression must have type ExpQ
a list of top-level declarations; ; the spliced expression must have type Q [Dec]
a type; the spliced expression must have type TypQ.
A expression quotation is written in Oxford brackets, thus:
[| ... |], where the "..." is an expression; the quotation has type ExpQ.
[d| ... |], where the "..." is a list of top-level declarations; the quotation has type Q [Dec].
[t| ... |], where the "..." is a type; the quotation has type TypQ.
Reification is written thus:
reifyDecl T, where T is a type constructor; this expression has type Dec.
reifyDecl C, where C is a class; has type Dec.
reifyType f, where f is an identifier; has type Typ.
Still to come: fixities
The data types and monadic constructor functions for Template Haskell are in the library Language.Haskell.THSyntax.
You can only run a function at compile time if it is imported from another module. That is, you can't define a function in a module, and call it from within a splice in the same module. (It would make sense to do so, but it's hard to implement.)
The flag -ddump-splices shows the expansion of all top-level splices as they happen.
If you are building GHC from source, you need at least a stage-2 bootstrap compiler to run Template Haskell. A stage-1 compiler will reject the TH constructs. Reason: TH compiles and runs a program, and then looks at the result. So it's important that the program it compiles produces results whose representations are identical to those of the compiler itself.
Template Haskell works in any mode (--make, --interactive, or file-at-a-time). There used to be a restriction to the former two, but that restriction has been lifted.
To help you get over the confidence barrier, try out this skeletal worked example. First cut and paste the two modules below into "Main.hs" and "Printf.hs":
{- Main.hs -} module Main where -- Import our template "pr" import Printf ( pr ) -- The splice operator $ takes the Haskell source code -- generated at compile time by "pr" and splices it into -- the argument of "putStrLn". main = putStrLn ( $(pr "Hello") ) |
{- Printf.hs -} module Printf where -- Skeletal printf from the paper. -- It needs to be in a separate module to the one where -- you intend to use it. -- Import some Template Haskell syntax import Language.Haskell.THSyntax -- Describe a format string data Format = D | S | L String -- Parse a format string. This is left largely to you -- as we are here interested in building our first ever -- Template Haskell program and not in building printf. parse :: String -> [Format] parse s = [ L s ] -- Generate Haskell source code from a parsed representation -- of the format string. This code will be spliced into -- the module which calls "pr", at compile time. gen :: [Format] -> ExpQ gen [D] = [| \n -> show n |] gen [S] = [| \s -> s |] gen [L s] = string s -- Here we generate the Haskell code for the splice -- from an input format string. pr :: String -> ExpQ pr s = gen (parse s) |
Now run the compiler (here we are using a "stage three" build of GHC, at a Cygwin prompt on Windows):
ghc/compiler/stage3/ghc-inplace --make -fglasgow-exts -package haskell-src main.hs -o main.exe |
Run "main.exe" and here is your output:
$ ./main Hello |