8

The following doesn't compile:

import Language.Haskell.TH
makeAlpha n = [d| data Alpha = Alpha $(conT n) deriving (Show, Read) |]

I can't make out what the error means at all:

Can't derive instances where the instance context mentions
type variables that are not data type parameters
  Offending constraint: Show t_d
When deriving the instance for (Show Alpha)
In the Template Haskell quotation
  [d| data Alpha = Alpha $(conT n) deriving (Show, Read) |]
In the expression:
  [d| data Alpha = Alpha $(conT n) deriving (Show, Read) |]

Is it possible to do derivations like this?

  • I think the problem might be that it's trying to derive the instances before it gets *n*; i.e. it's trying to expand your splice to contain the instances, but can't, because it doesn't know what `$(conT n)` looks like. Not sure, though. – ehird Dec 31 '11 at 18:03
  • I thought similarly, but I often can't be sure what's allowed and not with Template Haskell ... In this scenario I think it's obvious it can't derive the instances yet and needs to wait for the use of the function to expand. Is this a bug? –  Dec 31 '11 at 18:05
  • Hmm, wait, shouldn't it be `data Alpha = $(conT n)` or something? I think what you have now is a type error, at least from glancing at [the definition of `Dec`](http://hackage.haskell.org/packages/archive/template-haskell/2.6.0.0/doc/html/Language-Haskell-TH-Syntax.html#t:Dec). – ehird Dec 31 '11 at 18:08
  • I want Alpha to take a value of type that I determine later. If you remove derivation, it works and the compiler generates the right code. –  Dec 31 '11 at 18:17

1 Answers1

7

This problem arises because TH quotes are type checked when they are compiled, with splices replaced by variables. This is usually a good idea, because it allows many kinds of problems to be detected before the splice is run, but in some cases this can make the compiler wrongfully reject a splice that would generate valid code.

In this case, this means that the compiler tries to check this code:

data Alpha = Alpha t deriving (Show, Read)

This doesn't work because the derived Show and Read instances need to use Show and Read for t, but since t is not a type parameter of Alpha, it cannot add the necessary constraints. Of course, when this splice is run, t is replaced by a concrete type, so the appropriate instances will be available without the need for any constraints, so this is one of the cases where the compiler is being over-cautious.

The workaround is to not use quoting, but instead use TH combinators, which are not subject to these extra checks. It's messy, but it works:

makeAlpha n = sequence [dataD (cxt []) alpha []
                [normalC alpha [strictType notStrict (conT n)]] [''Show, ''Read]]
  where alpha = mkName "Alpha"

There has been some talk about relaxing the checks done on quotes, but for now you'll just have to deal with it.

hammar
  • 138,522
  • 17
  • 304
  • 385