3

For example:

let context = sequence [classP (mkName "Eq") [varT (mkName "a")]]
in
  [d| instance $(context) => Bar (Foo a) where
         quux _ = undefined
  |]

The result that I want is instance Eq a => Bar (Foo a) where quux _ = undefined, however, Template Haskell complains, rightly, that context has the type Q Cxt instead of the expected Q Type.

Is there a way to specify the constraints of the instance declaration without having to use the constructor InstanceD directly?

Sebastian Mendez
  • 661
  • 9
  • 18
  • 2
    Naturally if TH expects a TypeQ you should give it a TypeQ. I thought that you should be able to change `context` to `conT ''Eq \`appT\` varT (mkName "a")` - this just produces a TypeQ. However, when I try to compile it, I get an error I had never seen up until this moment: `Exotic predicate type not (yet) handled by Template Haskell $context`. So it looks like you are out of luck. – user2407038 Mar 05 '15 at 02:13

1 Answers1

1

I don't think Template Haskell currently supports splicing type contexts directly (this is just a guess).

However, you can define a function to append the contexts on all DecsQ typeclass instances:

appendInstancesCxtQ :: DecsQ -> Q Cxt -> DecsQ
appendInstancesCxtQ = liftM2 $ \ds c -> map (`appendInstanceCxt` c) ds
  where appendInstanceCxt (InstanceD c ts ds) c' = InstanceD (c++c') ts ds
        appendInstanceCxt d                   _  = d

Then, you can use it to modify the result of the quasi-quoted expression:

let v = varT $ mkName "a"
    context = sequence [[t| Eq $v |]]
in
  [d| instance Bar (Foo $v) where
        quux _ = undefined
  |] `appendInstancesCxtQ` context

It does not look as nice, but it is still better than building everything on top of the InstanceD constructor.

Rudy Matela
  • 6,310
  • 2
  • 32
  • 37