[GHC] #7492: Generic1 deriving: Can we replace Rec1 f with f :.: Par1?

GHC ghc-devs at haskell.org
Mon Dec 7 17:49:12 UTC 2015


#7492: Generic1 deriving: Can we replace Rec1 f with f :.: Par1?
-------------------------------------+-------------------------------------
        Reporter:  spl               |                Owner:  dreixel
            Type:  feature request   |               Status:  new
        Priority:  normal            |            Milestone:  8.0.1
       Component:  Compiler          |              Version:  7.7
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by RyanGlScott):

 The changes Pedro was alluding to involving `DataKinds` have now been
 implemented (#9766), so that's no longer holding this back. It would be
 interesting to talk about the pros and cons of changing `Rec1 f` to `f :.:
 Par1`

 The obvious pro is that is removes a redundant representation type, making
 `(:.:)` the sole way to talk about type constructors being applied to the
 type parameter. I also suspect that this change would make #8516 easier,
 but that's a different story.

 There are two cons that I can see:

 1. All code that declares instances for `Rec1` would eventually have to be
 changed. We have a much better story for deprecation than we used to,
 though, so this isn't a dealbreaker.

 2. `Generic1` instances involving `Rec1` have different instance heads
 than instances involving `(:.:)`. To be more specific, consider this data
 type:

     {{{#!hs
     newtype T1 a = T1 (T2 a) deriving Generic1
     }}}

     Right now, this would be derived `Generic1` instance:

     {{{#!hs
     instance Generic1 T1 where
       type Rep1 T1 =
         D1 ('MetaData "T1" "Module" "package" 'True)
           (C1 ('MetaCons "T1" 'PrefixI 'False)
             (S1 'NoSelector (Rec1 T2)))
       from1 (T1 a) = M1 (M1 (M1 (Rec1 a)))
       to1 (M1 (M1 (M1 a))) = T1 (unRec1 a)
     }}}

     But with this proposal, it would be this:

     {{{#!hs
     instance Generic1 T1 where
       type Rep1 T1 =
         D1 ('MetaData "T1" "Module" "package" 'True)
           (C1 ('MetaCons "T1" 'PrefixI 'False)
             (S1 'NoSelector (T2 :.: Par1)))
       from1 (T1 a) = M1 (M1 (M1 (Comp1 (fmap Par1 a))))
       to1 (M1 (M1 (M1 a))) = T1 (fmap unPar1 (unComp1 a))
     }}}

     There's one very important difference here. The latter instance
 requires that `T2` is a `Functor` instance, whereas the former instance
 does not! It would be interesting to know if this would prevent some
 datatypes in the wild from being `Generic1` instances. For example,
 suppose `newtype T2 a = T2 (a -> Int)`. Then we couldn't make `T2` a
 `Functor`, and thus we couldn't make `T1` `Generic1`!

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


More information about the ghc-tickets mailing list