[GHC] #15969: Generic1 deriving should use more coercions

GHC ghc-devs at haskell.org
Thu Nov 29 11:51:49 UTC 2018


#15969: Generic1 deriving should use more coercions
-------------------------------------+-------------------------------------
        Reporter:  dfeuer            |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:  8.8.1
       Component:  Compiler          |              Version:  8.6.2
      Resolution:                    |             Keywords:  Generics,
                                     |  Deriving
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:                    |
-------------------------------------+-------------------------------------

Comment (by RyanGlScott):

 This is a very interesting observation. I, too, have been rather annoyed
 by the fact that `Generic1` requires using `fmap` to implement instances
 involving `(:.:)`. In fact, I've pondered using
 `Coercible`-plus-`QuantifiedConstraints` to get replace these `fmap`s in
 [https://gist.github.com/RyanGlScott/cca1a0605a3b460c4af073cfce3c15fb this
 gist]. (It comes with its
 [https://ghc.haskell.org/trac/ghc/ticket/8516#comment:7 own set of
 problems], which is why I haven't pursued the idea further.)

 Remarkably, however, this technique bypasses the need to use `fmap`
 entirely! I'm not sure why `Generic1` didn't pick this convention to start
 with—perhaps they wanted `(:.:)` to be right-associative as a sort of
 parallel the function composition operator `(.)`, which is also
 associative? I can't say.

 Unfortunately, `(:.:)` being right-associative //is// a well established
 convention at this point, and switching it to be left-associative would
 break lots of code in the wild. Most instances of `(:.:)` tend to look
 like this:

 {{{#!hs
 instance (Cls f, GCls g) => GCls (f :.: g) where
   gmeth = ...

 class Cls f where
   meth :: ...
   default meth :: (Generic1, GCls (Rep1 f)) => ...
   meth = ... gmeth ...

 class GCls f where
   gmeth :: ...
 }}}

 That is, you give the outer type `f` an instance of the "base" class
 (`Cls`) and the inner type `g` an instance of the "generified" class
 (`GCls`). If we made `(:.:)` left-associative, then we'd have to turn this
 convention around and instead define:

 {{{#!hs
 instance (GCls f, Cls g) => GCls (f :.: g) where
   gmeth = ...
 }}}

 Is the breakage worth it? I'm inclined to say "no", since if we're going
 to make a backwards-incompatible change to `GHC.Generics`, then our effort
 might be better spent incorporating a more modern generic programming
 library into GHC (call it `GHC.Generics2`, perhaps) and slowly deprecating
 `GHC.Generics` in favor of that one. And thankfully, most modern generic
 programming frameworks no longer use `(:.:)`, so it's simply a non-issue
 there.

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


More information about the ghc-tickets mailing list