
#10056: Inconsistent precedence of ~ -------------------------------------+------------------------------------- Reporter: crockeea | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.8.4 (Parser) | Keywords: Resolution: | Architecture: Operating System: Unknown/Multiple | Unknown/Multiple Type of failure: GHC rejects | Test Case: valid program | Blocking: Blocked By: | Differential Revisions: Related Tickets: | -------------------------------------+------------------------------------- Comment (by goldfire): Here's what I know about all of this, to the best of my knowledge: - Types do ''not'' "inherit" fixity from terms. The type family `(+) :: * -> * -> *` (or whatever kinds) is completely and totally unrelated to the term-level variable `(+) :: Num a => a -> a -> a`. - There is no way in a fixity declaration to specify what namespace you want the declaration to operate over. So, in (what I consider to be) a terrible hack, a fixity declaration will affect either or both of local term-level and type-level definitions. So, if you have {{{ (//) :: a -> a -> a (//) = ... type family (//) a b infixl 5 // }}} then ''both'' the term `(//)` and the type `(//)` get the given fixity. This isn't a case of one inheriting the fixity from the other or being at all related -- it's just a peculiar meaning given to a fixity declaration. - While the parser doesn't know what type a term has, it ''does'' know whether you're writing a term, a type, or a kind. So it can behave differently in each of these cases -- they're all syntactically distinct in Haskell source. - Traditional fixity declarations don't affect the parser. And, upon some thought, we realize they can't: a fixity declaration can't be acted upon until after (or in) the renamer, when we know where a symbol is declared. - `(~)` is parsed separately from the normal infix operators. Recall that `TypeOperators` used to require type-level operators to begin with `:`. `(~)` does not, and so it must be special. Now that `TypeOperators` has been changed, there actually doesn't seem to be a good reason to keep `(~)` special. It's declared (in `ghc-prim:GHC.Types`). It has magic in the solver, but there needs to be no magic dealing with naming or parsing. However, simply removing the magic causes several minor conundrums: - Do we require `TypeOperators` when `~` appears in source code? Currently, we don't. - Do we require `TypeFamilies` or `GADTs` when `~` appears in source code? Currently, we do, but if we drop the magic, this decision is suspect, especially if `~` isn't ever really acted on in the module (because it appears only on the RHS of a type synonym, say). - Should `(~)` be imported as part of the Prelude? If no, then a lot of code breaks. If yes, that implies that hiding the Prelude also hides `(~)`, breaking less code, but still breaking code. These issues are surmountable, perhaps, but when I looked at making `~` non-magical, I discovered both that it's technically quite straightforward and socially rather annoying for little benefit. I suppose there's a middle road where it's non-magical in the parser but magical in the renamer. When I realized how tangled this all was, I gave up, as I was just doing some cleaning. Now that bugs are actually appearing, there might be more incentive to come up with a consistent response. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/10056#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler