[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