small improvement to roles mechanism

Edward Kmett ekmett
Fri Oct 11 23:55:03 UTC 2013

I have to agree that I'm somewhat disturbed by the fact that we're pushing
this out and we're still finding issues with it this close to release. =(

It strikes me that the role machinery is going to be the cause of the
majority of the pain users have upgrading to 7.8, and if I try to pretend
to be Mark Lentczner for a bit, it makes it seem highly likely that it'd be
the kind of thing that keeps 7.8 from going into a Haskell Platform,
causing the groundhog to see his shadow, leaving us with another year of
7.4 or 7.6.x.

I know we're at the 5 yard line, but to metaphorically throw a bunch of
metaphors in a blender, if we had to make the uncomfortable decision to
perform triage and ask if it should be put off (at least enforcing) the
roles machinery to 7.10, so we can know we have it right, how much fallout
would there be? Off the top of my head, of course Joachim's work on
Coercible would be affected. What else?

One option might be to pull the teeth of role inference for 7.8 with
regards to GND, and turn bad roles use into a warning for a release cycle.
That would give the community a year to get role annotations in place
before generalized newtype deriving for their code just stopped working.

If we ship with this the way it stands, I don't foresee the community
reaction being good.

With its teeth pulled, then GND could proceed as before, but with the added
detailed warnings from the dictionary coercions helping to guide folks to
make the change. By the time we'd be enforcing correct role annotations
most folks would have them in place to silence the warnings.


On Fri, Oct 11, 2013 at 7:15 PM, Johan Tibell <johan.tibell at>wrote:

> Oh and let me add: it would have been nice to have the people actually
> making these change to have done an impact analysis on Hackage, instead of
> discovering potential issues a week or two before the release. Lets try to
> do that next time.
> On Fri, Oct 11, 2013 at 4:14 PM, Johan Tibell <johan.tibell at>wrote:
>> Let me start by saying that I'm happy we're trying to fix the GND
>> problem. Thanks for working on that.
>> That being said: is this ready for mainstream consumption? We're forcing
>> this on everyone without any language pragma or flags to opt-in/out. That
>> is bad if we're not sure we're doing the right thing in some cases or if
>> we're causing spurious failures. At ICFP I got the impression that very few
>> people will be affected, but Bryan's result suggests there are more people
>> than I thought.
>> On Thu, Oct 10, 2013 at 8:26 PM, Richard Eisenberg <eir at>wrote:
>>> In Bryan's recent test of GHC 7.8 against all of Hackage, there were
>>> three spurious errors caused by lack of role abstraction. Here are the
>>> class definitions where a nominal parameter is inferred, probably against
>>> the wishes of the author:
>>> from logict-0.2.3/Control.Monad.Logic.Class:
>>> > class (MonadPlus m) => MonadLogic m where
>>> >     msplit     :: m a -> m (Maybe (a, m a))
>>> from monadLib-3.5.2/MonadLib:
>>> > class (Monad m) => ReaderM m i | m -> i where
>>> >   ask :: m i
>>> from base/Control.Arrow:
>>> > class Arrow a => ArrowApply a where
>>> >     app :: a (a b c, b) c
>>> In each of these, the last parameter of the class is given a nominal
>>> role because it appears as the parameter of a type variable. However, in
>>> each case, it appears as the parameter of a *class* type variable. This
>>> means that, if we somehow knew that the class author wanted the class to be
>>> usable with GND, we could simply check every instance declaration for that
>>> class to make sure that the relevant concrete instantiation has the right
>>> role. For example, when the user writes, for example
>>> > instance ArrowApply Foo where ?
>>> we check that Foo's first parameter has a representational role. If it
>>> doesn't, then the instance is rejected.
>>> An alternative, somewhat heavier idea would be to represent roles as
>>> class constraints. We could have
>>> > class NextParamNominal (c :: k)
>>> > class NextParamRepresentational (c :: k)
>>> GHC could "generate" instances for every datatype definition. For
>>> example:
>>> > type role Map nominal representational
>>> > data Map k v = ?
>>> would induce
>>> > instance NextParamNominal Map
>>> > instance NextParamRepresentational (Map k)
>>> Users would not be able to write these instances -- they would have to
>>> be generated by GHC. (Alternatively, there could be no instances, just a
>>> little magic in the constraint solver. Somewhat like Coercible.)
>>> Then, the classes above would just have to add a superclass, like this:
>>> > class (Arrow a, NextParamRepresentational a) => ArrowApply a where
>>> >   app :: a (a b c, b) c
>>> The role inference mechanism would be made aware of role constraints and
>>> use this one to derive that ArrowApply is OK for GND.
>>> This "heavier" approach has a similar upshot to the first idea of just
>>> checking at instance declarations, but it is more customizable and
>>> transparent to users (I think).
>>> I'm not sure I'm advocating for this change (or volunteering to
>>> implement before the release candidate), but I wanted to document the idea
>>> and get any feedback that is out there. This would fix the breakage we've
>>> seen without totally changing the kind system.
>>> Thanks,
>>> Richard
>>> PS: Due credit is to migmit for suggesting the type-class idea on
>>> glasgow-haskell-users.
>>> _______________________________________________
>>> ghc-devs mailing list
>>> ghc-devs at
> _______________________________________________
> ghc-devs mailing list
> ghc-devs at
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the ghc-devs mailing list