On Oct 16, 2013, at 4:23 PM, Simon Peyton-Jones wrote:

> What it would mean is that, if we do decide to generalize roles further, 
> users would have one release that allows noticeably fewer uses of GND than 
> the one before or the one after it. On the other hand, if we're confident 
> that we're not going to tinker with roles more, then I see much stronger 
> reasons for releasing with 7.8.
>  
> I don’t think we know for sure.  But the way to find out is to release it.  
> If we don’t have a compiler that supports roles, no one will explore or use 
> them.  We do this all the time, and yes, Haskell is a bit less 
> smoothly-upgradable as a result.  But I think it’s worth it, otherwise we’d 
> be stuck in treacle.
>  
> Remember this is fixing a current unsoundness that can lead to un-caught 
> segmentation faults in user code.  That is a Jolly Good thing to fix, it not 
> just a snazzy feature that two people want.
>  
> Richard, how are you fixed at the moment?  Are you able to implement the new 
> GND check soon?  Or not?

OK. It sounds like we're all pushing forward here.

I should be able to implement within the next week, probably starting tomorrow, 
and possibly ending tomorrow, too. Not sure exactly how hard it will be.

Richard

>  
> Simon
>  
> From: Richard Eisenberg [mailto:e...@cis.upenn.edu] 
> Sent: 16 October 2013 18:29
> To: Simon Peyton-Jones
> Cc: Edward Kmett; ghc-devs
> Subject: Re: More GND + role inference woes
>  
> Please see my responses below. (Note: this was written before Edward's most 
> recent post, which will be addressed shortly.)
> Executive summary: Edward's problem is more general than the one that Simon 
> solves, but what Edward wants is actually not type safe.
>  
> On Oct 16, 2013, at 9:28 AM, Simon Peyton-Jones wrote:
> 
> 
> I think I know what to do about the GND + roles question.
>  
> First, the problem. Here’s an example:
>      class Trans t a where
>         foo :: t a -> t a
>  
>      newtype N x = MkN x deriving( Trans Maybe )
>  
> As things stand, Trans gets roles (representational, nominal).  The second 
> parameter ‘a’ gets a nominal role because we don’t know what ‘t’ will get 
> instantiated too.
>  
> As a result the attempted GND is rejected because of the new role stuff.  But 
> with 7.6.3 we’ll get an instance
>      instance Trans Maybe a => Trans Maybe (N a)
> from the GND mechanism.
>  
> Do I have this right?
>  
> This is a more specific instance of the problem. Yes, the case with `Trans` 
> does appear, but also cases like this:
>  
> class Functor f => Core f where
>   core :: ((forall g x. Functor g => (x -> g x) -> f x -> g (f x)) -> a) -> f 
> a
>  
> That's a nasty-looking type, but note the `g (f x)` that appears. Here, `f` 
> is used as a parameter to a type variable that *is not a class variable*. The 
> problem Simon describes is only the case where the applied type variable is a 
> class variable, and thus is known at `deriving` time.
>  
> To handle things like Core, we would need to have more proper role 
> abstraction, where we can assert that `g` has a parameter with a 
> representational role in order to infer `f` as a representational parameter 
> for Core. In Edward's `linear` package, the Linear.Affine module has this 
> definition:
>  
> newtype Point f a = P (f a)
>   deriving ( Eq, Ord, Show, Read, Monad, Functor, Applicative, Foldable
>            , Traversable, Apply, Bind, Additive, Metric, Core, R1, R2, R3, R4
>            , Fractional , Num, Ix, Storable, Epsilon
>            )
>  
> Of these derivings, the following currently fail: Traversable, Bind, Core, 
> R1, R2, R3, and R4. It is straightforward to fix Traversable with 
> DeriveTraversable (and a standalone instance). Bind will fixed by the change 
> in the GND check. But, Core and the Rs won't be and would have to be written 
> by hand.
> 
> 
>  
>  
>  
> Second, there is a Good Reason for the problem.  Suppose I said
>                 newtype N x = MkN x deriving( Trans D )
> where D was a data family.  Then the foo method for (D x) might seg-fault if 
> applied to a (D (N x)) value.  So the current GND is treading on very thin 
> ice, and it is ice that the author (Edward) does not control.  His clients 
> control it.
>  
> Do I have this right?
>  
> Yes.
> 
> 
>  
>  
> Third, there is an easy solution.  As Richard observed in a separate thread 
> about Coercible, GND does not attempt to build a coercion to witness
>      Trans Maybe x  ~R  Trans Maybe (N x)
>  
> Rather, it builds a dictionary for (Trans Maybe (N x)) thus
>      dTransMaybeN :: Trans Maybe x -> Trans Maybe (N x)
>      dTransMaybeN d = MkTrans (sel_foo d |> co)
>  
> where the (sel_foo d) selects  the foo method from d.  That is, we actually 
> cast the methods, not the dictionary as a whole.  So what we need is a 
> coercion between
>      Maybe x  ~R  Maybe (N x)
> Can we get that?  Yes of course!  Maybe has a representational role.
>  
> Bottom line: we should accept or reject a GND attempt not on the basis of the 
> role of the class, but rather on whether the method types are coercible.   
> Indeed, this is just what we agreed some days ago
> http://www.haskell.org/pipermail/glasgow-haskell-users/2013-October/024386.html
>  
> So I think this solves Edward’s problem below.
>  
>  
> Moreover, I think this solves the other failures in 
> http://www.haskell.org/pipermail/ghc-devs/2013-October/002961.html.  Here is 
> one example, in that email.  smallcheck has this:
> newtype Series m a = Series (ReaderT Depth (LogicT m) a)
>   deriving
>     ( …,  MonadLogic)
>  
> where logict defines MonadLogic thus:
>  
> class (MonadPlus m) => MonadLogic m where
>     msplit     :: m a -> m (Maybe (a, m a))
>  
> So the “bottom line” check above will attempt to find a cocercion betwem 
> msplit’s type with m=Series m, and with m=ReaderT Depth (LogitT m).  Right?
>  
> Yes.
> 
> 
>   So on the left of msplit’s arrow, we’ll ask can we prove
>  
>      Series m a ~R ReaderT Depth (LogicT m) a
>  
> Can we show that?  Yes, of course… that is the very newtype coercion for 
> Series.
>  
> Well, it's the right-hand side of the arrow that's more troublesome, but that 
> works out in this case, too.
> 
> 
>  
> In short, I think we are fine, once Richard has implemented the new GND test.
>  
> Am I wrong?
>  
> It depends on what "fine" is.
>  
> The new GND check will allow more deriving, but not all that Edward wants. 
> BUT, the ones that (the new) GND doesn't allow aren't actually safe! In the 
> Point example, using GND on Core and the Rs might actually lead to a type 
> error, depending on the instantiation of local type variables within the 
> methods in those classes. For example, if the `g` variable in Core's `core` 
> method is instantiated with a type with a nominal parameter, there could be 
> trouble.
>  
> So, I disagree with Edward's original claim at the top of this thread that 
> roles cause havoc here: they don't cause havoc, they catch latent type errors!
>  
> On the other hand, I agree that with more machinery (that is, a constraint on 
> `g` about its parameter's role) we could potentially allow all the derived 
> instances that Edward wants.
>  
> What I'm worried about is the user experience like the following:
> - 7.8 comes out: A bunch of deriving clauses have to be expanded to 
> hand-written instances. Annoying, and with runtime cost.
> - 7.10 comes out: A bunch of those expanded instances now can be rolled back 
> into derived ones, with some extra, not-backward-compatible annotations (that 
> is, the constraints on variables like `g`). Annoying, and a real maintenance 
> headache.
>  
> What it would mean is that, if we do decide to generalize roles further, 
> users would have one release that allows noticeably fewer uses of GND than 
> the one before or the one after it. On the other hand, if we're confident 
> that we're not going to tinker with roles more, then I see much stronger 
> reasons for releasing with 7.8.
>  
> Richard

_______________________________________________
ghc-devs mailing list
ghc-devs@haskell.org
http://www.haskell.org/mailman/listinfo/ghc-devs

Reply via email to