[GHC] #11345: Template Haskell's handling of infix GADT constructors is broken
GHC
ghc-devs at haskell.org
Wed Jan 6 03:55:13 UTC 2016
#11345: Template Haskell's handling of infix GADT constructors is broken
-------------------------------------+-------------------------------------
Reporter: RyanGlScott | Owner: RyanGlScott
Type: bug | Status: new
Priority: normal | Milestone:
Component: Template Haskell | Version: 8.1
Resolution: | Keywords:
Operating System: Unknown/Multiple | Architecture:
Type of failure: Incorrect result | Unknown/Multiple
at runtime | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Changes (by RyanGlScott):
* owner: => RyanGlScott
Comment:
Actually, I realized that I was a little too careless in writing solutions
2 and 3—to the point where I skipped over an important detail: `InfixC`
and `reifyFixity` serve distinct purposes. `InfixC` just tells you that a
constructor was ''declared'' infix rather than prefix, i.e., it's the
difference between
{{{#!hs
data T1 a = T1 a a
}}}
and
{{{#!hs
data T2 a = a `T2` a
}}}
But it tells you nothing about its actual fixity ''when used as an infix
operator''. In fact, calling `reifyFixity` on both `'T1` and `'T2` would
yield the same answer (`Fixity 9 InfixL`) since neither have an explicit
fixity declaration.
This is a minor distinction, but an important one. As a motivating
example, when a datatype has a derived `Show` instance:
* If one of its constructors is declared prefix, then the constructor will
be shown before its fields, and the fields will always be shown with
precedence 11. This is regardless of whether a fixity declaration is
present.
* If one of its constructors is declared infix, then the constructor will
be shown between its two arguments, and the fields will shown according to
the precedence in the fixity declaration plus 1 (if none is present, it
defaults to 9+1).
This is extremely important for GADTs because it is a special case. A GADT
constructor is only considered to be declared infix if (a) it is an
operator symbol, (b) it has two arguments, (c) it has a fixity
declaration. Only then would a derived `Show` instance for a GADT
constructor show the constructor between its arguments.
For these reasons, proposals 2 and 3 above aren't quite accurate:
* `InfixC` can't be subsumed under `NormalC` neatly because they discern a
property of the datatype declaration that can't necessarily be gleaned
from `reifyFixity`. Unless you were to add another field to `NormalC` to
mark whether it was declared infix, that it—but that is another breaking
change.
* `InfixC` can't be subsumed under `RecC` at all, since if a constructor
has records, it is automatically considered not to be declared infix.
Considering all this, proposal 1 looks by far the most attractive in terms
of ease of implementation and the least API changes (barring
`GadtC`/`RecGadtC`). I think I'll go ahead and add an `InfixGadtC`
constructor to `Con`. Any objections?
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11345#comment:1>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list