[GHC] #8516: Add (->) representation and the Invariant class to GHC.Generics

GHC ghc-devs at haskell.org
Wed Dec 23 18:10:22 UTC 2015


#8516: Add (->) representation and the Invariant class to GHC.Generics
-------------------------------------+-------------------------------------
        Reporter:  nfrisby           |                Owner:
            Type:  feature request   |               Status:  new
        Priority:  low               |            Milestone:
       Component:  Compiler (Type    |              Version:  7.7
  checker)                           |
      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):

 Well, I had previously thought one could get away with not considering
 `Invariant`, but after thinking about it some more, having `Invariant` is
 crucial for this new feature to be compositional.

 We'd add two new data types:

 {{{#!hs
 infixr 4 :->:, :->-:
 newtype (f :->: r)  p = ContraArrow1 { unContraArrow1 :: f p -> r   }
 newtype (f :->-: g) p = InvArrow1    { unInvArrow1    :: f p -> g p }
 }}}

 And, if we [https://ghc.haskell.org/trac/ghc/ticket/7492 change] `Rec1 f`
 to `f :.: Par1`, then we can also define the following for symmetry:

 {{{#!hs
 infixr 4 :>-:
 type (r :>-: f) = ((->) r) :.: f
 }}}

 (I've adopted a pretty arbitrary naming scheme where hyphens (`-`) denote
 occurrences of the type parameter. Feel free to suggest other names.)

 Then we can generate instances for data types no matter which side of an
 arrow a type parameter might occur. Here is an example:

 {{{#!hs
 newtype Endo a = Endo (a -> a) deriving Generic1

 instance Invariant Endo where
   invmap f g (Endo x) = Endo (f . x . g)

 ==>

 instance Generic1 Endo where
   type Rep1 Endo = D1 ... (C1 ... (S1 ... (Par1 :->-: Par1)))
   to1 (M1 (M1 (M1 c))) = Endo ((.) (invCompose unPar1 Par1) unInvArrow1 c)
   from1 (Endo c) = M1 (M1 (M1 ((.) InvArrow1 (invCompose Par1 unPar1) c)))

 invCompose :: (c -> d) -> (a -> b) -> (b -> c) -> a -> d
 invCompose = \f g h x -> f (h (g x))
 }}}

 So far, so good. But if we define something like this:

 {{{#!hs
 newtype Endo2 a = Endo2 (Endo a) deriving Generic1
 }}}

 Then things become awkward. GHC would attempt to generate an instance like
 this:

 {{{#!hs
 instance Generic1 Endo2 where
   type Rep1 Endo2 = D1 ... (C1 ... (S1 ... (Endo :.: Par1)))
   to1 (M1 (M1 (M1 c))) = Endo2 ((.) (fmap unPar1) unComp1 c)
   from1 (Endo2 c) = M1 (M1 (M1 ((.) Comp1 (fmap Par1) c)))
 }}}

 But this will never work, because it assumes `Endo` is a `Functor`
 instance, which can't happen. This is quite a problem: we can make one
 datatype a `Generic1` instance, but we can't make a simple `newtype`
 wrapper around it a `Generic1` instance!

 However, if we changed the way GHC generated code for the `:.:` case to
 assume that the outermost datatype is an `Invariant` instance, not a
 `Functor` instance, then it would work:

 {{{#!hs
 instance Generic1 Endo where
   type Rep1 Endo = D1 ... (C1 ... (S1 ... (Par1 :->-: Par1)))
   to1 (M1 (M1 (M1 c))) = Endo ((.) (invCompose unPar1 Par1) unInvArrow1 c)
   from1 (Endo c) = M1 (M1 (M1 ((.) InvArrow1 (invCompose Par1 unPar1) c)))
 }}}

 Of course, this would mean bringing in `Invariant` to `base`, and it makes
 an assumption that most datatypes you'd find in the wild are `Invariant`
 instances already. As I mentioned above, trying to make `Invariant` a
 superclass of `Functor` is a hard sell.

 Futhermore, I'm not sure if we'd really gain anything after all this
 breakage besides being able to derive `Functor` and `Invariant` instances
 generically. I'm not convinced the benefits outweigh the potential
 heartburn in this case.

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


More information about the ghc-tickets mailing list