[Haskell-cafe] known, I know: class contexts and mutual recursion

Conor McBride ctm at cs.nott.ac.uk
Wed Nov 29 13:14:56 EST 2006

Hi folks

I just tripped over the "Contexts differ in length" error message. I 
know it's not a new problem, but I thought I'd enquire as to its status. 
For those of you who haven't seen it, here's an example, contrived but 

 > data Thing
 >   = Val Int
 >   | Grok Thing (Maybe Int -> Int)

 > eval :: Monad m => Thing -> m Int
 > eval (Val i) = return i
 > eval (Grok t f) = return (f (eval t))

My eval function compiles ok. See? The recursive call to eval targets 
the Maybe monad, so I get

*Mmm> eval (Grok (Val 5) (maybe 0 (1 +))) :: Maybe Int
Just 6

However, when I try to decompose eval as a pair of mutually recursive 
functions, namely

 > foo :: Monad m => Thing -> m Int
 > foo (Val i) = return i
 > foo (Grok t f) = return (goo t f)

 > goo :: Thing -> (Maybe Int -> Int) -> Int
 > goo t f = f (foo t)

I get

   Contexts differ in length
   When matching the contexts of the signatures for
     foo :: forall (m :: * -> *). (Monad m) => Thing -> m Int
     goo :: Thing -> (Maybe Int -> Int) -> Int
   The signature contexts in a mutually recursive group should all be 

Poking about on the web, I got the impression that this was a known 
infelicity in ghc 6.4 (which I'm using), due to be ironed out. However, 
an early-adopting colleague with 6.6 alleges that foo-goo is still 
poisonous. I'm wondering what the story is. I mean, is there some nasty 
problem lurking here which prevents the lifting of this peculiar 

I'm not in a panic about this. I have a workaround for the problem as I 
encountered it in practice. Mind you, it's the sort of thing that's 
likely to happen more often, the more you localise the effects you tend 
to use. In the above, goo doesn't throw exceptions; rather, because goo 
has a handler, it can offer a /local/ exception-throwing capability to foo.



More information about the Haskell-Cafe mailing list