
Dear Cafe, Thanks to the kind help of Adam and Richard I now can generate instances for parametrized data types with Template Haskell. However, I still struggle adding class constraints to the type variables. I try to follow the derive_show example of Ian Lynagh but it seems some interfaces have changed since he wrote "Template Haskell: A Report From The Field". I generate MyClass constraints for a set of type variables with the following code:
genCxt :: [TyVarBndr] -> Q Cxt genCxt tvs = return [classp $ map (\v -> (tvname v)) tvs]
classp :: [Type] -> Pred classp = ClassP (mkName "TH_playground.MyClass")
tvname :: TyVarBndr -> Type tvname (PlainTV name ) = ConT name tvname (KindedTV name _) = ConT name
To be able to generate MyClass instances with:
genInstance :: Q Type -> Q [Dec] genInstance qt = do { t <- qt ; n <- case t of (ForallT tvs _ t') -> [t| MyClass $(return t') |] _ -> [t| MyClass $qt |] ; m <- genMethod qt ; c <- case t of (ForallT tvs _ t') -> genCxt tvs _ -> return [] ; return [InstanceD c n m] }
Up to here, everything type checks and I can build the module where I defined it. In a different module I try to generate an instance for MyData a:
data MyData a = MyCon a $(genInstance [t| forall a.MyData a |])
This however does not seems to go down well with the compiler. || Illegal type constructor or class name: `a' || When splicing a TH declaration: || instance TH_playground.MyClass a_0 => TH_playground.MyClass (Main.MyData a_0) || where myMethod (Main.MyCon x_1) = "todo" This error message confuses me because it seems to complain about the type variable a in the generate instance, but in the generated instance this variable is renamed to a_0. Also, when I copy the generated code from the error message the ghc is completely happy. Without the class constraints the generated instance type checks and compiles as well:
genCxt _ = return []
But I would like to apply myMethod on the fields in parametrized data types, which is not correct without the class constraints. Did I find a bug in ghc's Template Haskell implementation or am I doing something silly? Thanks, Maarten