[GHC] #13153: Several Traversable instances have an extra fmap

GHC ghc-devs at haskell.org
Fri Jan 20 20:24:20 UTC 2017


#13153: Several Traversable instances have an extra fmap
-------------------------------------+-------------------------------------
        Reporter:  dfeuer            |                Owner:  dfeuer
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:  8.4.1
       Component:  Core Libraries    |              Version:  8.1
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  Runtime           |  Unknown/Multiple
  performance bug                    |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------
Changes (by RyanGlScott):

 * cc: goldfire (added)


Comment:

 > Can you explain how higher-kinded roles would help?

 Hm, I thought I meant higher-kinded roles, but now I recall Richard
 telling me that he thought those were inferior to normal roles +
 [https://ghc.haskell.org/trac/ghc/ticket/2256 implication constraints]
 (I've cc'd him in case I totally butcher this). So let me instead explain
 how those would help :)

 The current issue that prevents you from writing this:

 {{{#!hs
 newtype Wrapped inner a = Wrap { unwrap :: inner a }
   deriving (Functor, Foldable)

 instance Traversable inner => Traversable (Wrapped inner) where
   traverse = coerce traverse
 }}}

 is that we need to coerce from `(a -> f b) -> inner a -> f (inner b)` to
 `(a -> f b) -> Wrapped a -> f (Wrapped b)` for some `f`. That is, we need
 to prove `Coercible (f (inner b)) (f (Wrapped b))`. But we don't know this
 //a priori//. `f` is some arbitrary type variable, so we have to be
 conservative and assume its role is nominal. That prevents us from
 coercing underneath `f`, so we can't conclude `Coercible (f (inner b)) (f
 (Wrapped b))`.

 But what if we could modify the `Traversable` instance to require this
 coercibility property as part of the instance context? It sure would be
 great if we could just write this:

 {{{#!hs
 instance (Coercible (f (inner b)) (f (Wrapped inner b)), Traversable
 inner) => Traversable (Wrapped inner) where
   traverse :: forall f a b. Applicative f => (a -> f b) -> Wrapped inner a
 -> f (Wrapped inner b)
   traverse = coerce (traverse :: (a -> f b) -> Wrapped inner a -> f
 (Wrapped inner b))
 }}}

 But sadly, this won't work, since the `b` and the `f` in in the instance
 context can't scope over the class methods.

 What [https://ghc.haskell.org/trac/ghc/ticket/9123#comment:29 implication
 constraints] would let you do here is write this:

 {{{#!hs
 instance (forall f b. Applicative f => Coercible (f (inner b)) (f (Wrapped
 inner b)), Traversable inner) => Traversable (Wrapped inner) where
   traverse :: forall f a b. Applicative f => (a -> f b) -> Wrapped inner a
 -> f (Wrapped inner b)
   traverse = coerce (traverse :: (a -> f b) -> Wrapped inner a -> f
 (Wrapped inner b))
 }}}

 Notice that we're now able to stick a `forall` inside of an instance
 context, something which GHC currently forbids! The idea here being that
 this `forall f a b. Applicative f => Coercible (f (inner b)) (f (Wrapped
 inner b))` would get fed into the constraint solver and could be used to
 conclude that `Coercible (f (inner b)) (f (Wrapped b))` works for //any//
 `f` and `b` (where `f` is `Applicative`).

 But do keep in mind that user-visible implication constraints are nothing
 but a feature request at the moment, so all the above is hypothetical.
 Until some wonderful day in the future when we have this, the escape hatch
 is `unsafeCoerce`.

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13153#comment:9>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list