
Hi all, I've had a curious bug report [1] for haskell-src-exts, pointing to a difference in behavior between haskell-src-exts and GHC. Digging further, it seems to me like GHC is behaving quite strange in this instance, but since we don't have formal documentation for the extensions I can't be sure. I'm *almost* convinced this is a bug in GHC, but with these type extensions I can never be quite sure. Thus I'm putting it out here in the hope that someone will either explain why it is this way, or tell me to go file a bug report. The gist of it is the following piece of code:
multipleCtx :: Eq a => Show a => a multipleCtx = undefined
GHC accepts this code, while haskell-src-exts requires parentheses around the latter part of the signature, i.e. Eq a => (Show a => a). The difference is the following productions haskell-src-exts:
ctype :: { PType } : 'forall' ktyvars '.' ctype | context '=>' type | type
GHC:
ctypedoc :: { LHsType RdrName } : 'forall' tv_bndrs '.' ctypedoc | context '=>' ctypedoc | gentypedoc
Notice GHC's recursive call to ctypedoc after the =>. I have no idea what the doc suffix on the production is intended to indicate though - and I was curious to find a separate set of rules that don't have that suffix:
ctype :: { LHsType RdrName } : 'forall' tv_bndrs '.' ctype | context '=>' type | type
This one looks just like the one that haskell-src-exts uses - type instead of ctype after the =>. So what's the difference between the two in GHC? Looking further, the former is used in top-level type signatures, while the latter is used for pretty much everything else. In particular, you can't put a ctypedoc inside parentheses, there you would have to use ctype. So while GHC accepts the above definition, it rejects e.g. the (seemingly) equivalent
multipleCtx :: (Eq a => Show a => a) multipleCtx = undefined
My guess would be that there's a bug here, and that it's the recursive call to ctypedoc that is at fault, it should really be gentypedoc. On the other hand there's no problem parsing either, so there's no technical reason not to allow chained contexts without parentheses, even though I personally think it looks quite awkward. Enough rambling - can someone make me the wiser? Cheers, /Niklas [1] http://trac.haskell.org/haskell-src-exts/ticket/37

2009/6/18 Niklas Broberg
GHC:
ctypedoc :: { LHsType RdrName } : 'forall' tv_bndrs '.' ctypedoc | context '=>' ctypedoc | gentypedoc
Notice GHC's recursive call to ctypedoc after the =>. I have no idea what the doc suffix on the production is intended to indicate though - and I was curious to find a separate set of rules that don't have that suffix:
The doc suffix says "can contain Haddock comments".
ctype :: { LHsType RdrName } : 'forall' tv_bndrs '.' ctype | context '=>' type | type
This one looks just like the one that haskell-src-exts uses - type instead of ctype after the =>.
You're not looking at the latest version of the code. I'm guessing you're looking at the stable version instead of the HEAD. In HEAD we have:
ctypedoc :: { LHsType RdrName } : 'forall' tv_bndrs '.' ctypedoc { LL $ mkExplicitHsForAllTy $2 (noLoc []) $4 } | context '=>' ctypedoc { LL $ mkImplicitHsForAllTy $1 $3 } -- A type of form (context => type) is an *implicit* HsForAllTy | ipvar '::' type { LL (HsPredTy (HsIParam (unLoc $1) $3)) } | typedoc { $1 }
This should accept both
multipleCtx :: (Eq a => Show a => a) multipleCtx = undefined
and
multipleCtx :: Eq a => Show a => a multipleCtx = undefined
The reason why ctypedoc and ctype were so different before, is because they drifted apart after ctypedoc was added. ctype was changed (I think during implementation of the TypeFamilies extension) without any changes to ctypedoc. This was fixed in HEAD not so long ago. If you need more information I can dig up the trac ticket :-) David

You're not looking at the latest version of the code. I'm guessing you're looking at the stable version instead of the HEAD.
Indeed, I'm looking at the source distribution for 6.10.3, since that's the reference version I use to test the files.
ctypedoc :: { LHsType RdrName } : 'forall' tv_bndrs '.' ctypedoc { LL $ mkExplicitHsForAllTy $2 (noLoc []) $4 } | context '=>' ctypedoc { LL $ mkImplicitHsForAllTy $1 $3 } -- A type of form (context => type) is an *implicit* HsForAllTy | ipvar '::' type { LL (HsPredTy (HsIParam (unLoc $1) $3)) } | typedoc { $1 }
This should accept both
multipleCtx :: (Eq a => Show a => a) multipleCtx = undefined
and
multipleCtx :: Eq a => Show a => a multipleCtx = undefined
The reason why ctypedoc and ctype were so different before, is because they drifted apart after ctypedoc was added. ctype was changed (I think during implementation of the TypeFamilies extension) without any changes to ctypedoc. This was fixed in HEAD not so long ago.
Thanks a lot for the information, then I know. So the correct thing to do is to put a ctype in the recursive position after the context. I sorely wish these things were better documented... Cheers, /Niklas

| > The reason why ctypedoc and ctype were so different before, is because | > they drifted apart after ctypedoc was added. ctype was changed (I | > think during implementation of the TypeFamilies extension) without any | > changes to ctypedoc. This was fixed in HEAD not so long ago. | | Thanks a lot for the information, then I know. So the correct thing to | do is to put a ctype in the recursive position after the context. I | sorely wish these things were better documented... Me too. But you know the reason: so much to do, so little time. Plus, if code drifts apart from code (as it did above), you may imagine that document drifts apart from code even more. The best thing to do, I think, is to comment the code liberally. I particularly recommend the Note [blah] comments described in http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle If you'd like to add some such clarifying notes to Parser.y.pp, that'd be great. We'd gladly check them for veracity! Simon
participants (3)
-
David Waern
-
Niklas Broberg
-
Simon Peyton-Jones