Using Template Haskell for deriving instances

Derek Elkins ddarius@hotpop.com
Tue, 15 Jul 2003 11:36:34 -0400


On Tue, 15 Jul 2003 14:49:41 +0200
Carsten Schultz <carsten@gnocchi.dialup.fu-berlin.de> wrote:

> Hi,
> 
> is any workable example code for using Template Haskell to generate
> instance declarations available, eg the function `genEq' mentioned in
> the Template Haskell paper?

This is a module I made to warmup with TH.  Unfortunately, this was back
with 5.05 and I'm pretty sure the names and data structures have been
changed.  Hopefully, it's a relatively decent example of how to do this,
it did seem to work at the time.  When I work with TH again, I'd
like to make a fairly general deriving framework, however gmap
by itself might get you most of the way there.  Anyways, if you are
interested in TH you should probably join the Template Haskell mailing
list.

module GenNFData ( genNFData ) where

import Strategies
import Language.Haskell.THSyntax

{-
data Tree a b = EmptyTree | Leaf a | Branch b (Tree a b) (Tree a b)

$(genNFData $ reifyDecl Tree)
==>
instance (NFData a, NFData b) => NFData (Tree a b) where
    rnf EmptyTree = ()
    rnf (Leaf x) = rnf x
    rnf (Branch v l r) = seq (rnf v) (seq (rnf l) (rnf r))
-}

genNFData :: Decl -> Q [Dec]
genNFData dcl = do
    (Data _ nme vars ctors _) <- dcl
    x <- gensym "a"
    let vs = map tvar vars
        repNFD = namedTyCon "NFData" {-[t| NFData |]-}
        xs = foldl1 tapp (tcon (TconName nme) : vs)
    sequence [inst (ctxt $ map (tapp repNFD) vs) (tapp repNFD xs) 
                        [fun "rnf" (map mkRnf ctors)]]
  where mkRnf (Constr n []) = clause [pcon n []] (normal $ [| () |]) []
        mkRnf (Constr n as) = do
            ss <- mapM (const $ gensym "a	") as
            clause [pcon n (map pvar ss)] 
                (normal $ foldr1 (\x y -> [| seq $x $y |])
                                 (map (\x -> [| rnf $(var x) |]) ss))
                []