GHC: Ticket #8516: Add (->) representation and the Invariant class to GHC.Generics
http://ghc.haskell.org/trac/ghc/ticket/8516
<p>
We currently disallow any use of the parameter in the domain of (->).
</p>
<pre class="wiki">newtype F a = F ((a -> Int) -> Int) deriving Generic1
<interactive>:4:38:
Can't make a derived instance of `Generic1 (F g)':
Constructor `F' must use the last type parameter only as the last argument of a data type, newtype, or (->)
In the data declaration for `F'
</pre><p>
DeriveFunctor succeeds for this F.
</p>
<p>
I'd like to add this representation type to GHC.Generics and DeriveGeneric.
</p>
<pre class="wiki">newtype (f :->: g) a = FArrow1 (f a -> g a)
</pre><p>
We could then represent the first example above. We could also derive the more interesting Generic1 (F g).
</p>
<pre class="wiki">newtype F g a = F (g a -> Int) deriving Generic1
type instance Rep1 (F g) = Rec1 g :->: Rec0 Int
instance Generic1 (F g) where
to x = F $ unRec0 . unArrow1 x . Rec1
from (F x) = FArrow1 $ Rec0 . x . unRec1
</pre><p>
Admittedly, there's not many generic definitions impeded by not having (:->:). Contra- and in-variant types are uncommon.
</p>
<p>
I'm suggesting this feature without strong motivating examples because I think this would streamline the implementation of -XDeriveGenerics in some ways while also making it more general — assuming that we added the Invariant class to base or ghc-prim.
</p>
<pre class="wiki">class Invariant t where
invmap :: (a -> b) -> (b -> a) -> t a -> t b
invmap_covariant :: Functor t => (a -> b) -> (b -> a) -> t a -> t b
invmap_covariant f _ = fmap f
instance (Invariant f,Invariant g) => Invariant (FArrow f g) where
invmap co contra (FArrow h) = FArrow $ invmap co contra . h . invmap contra co
</pre><p>
(Of course, Invariant should be a super class of Functor. :/ )
</p>
<p>
Now we can handle quite involved examples:
</p>
<pre class="wiki">newtype F g h a = F (g (h a)) deriving Generic1
instance Invariant g => Generic1 (F g h) where
to x = invmap unRec1 Rec1 $ unComp1 x
from (F x) = Comp1 $ invmap Rec1 unRec1
</pre><p>
All of that said, I'm mostly opening this ticket so I can get feedback on difficulties I might not be anticipating and have a place to reference from the compiler source code comments.
</p>
en-usGHChttp://ghc.haskell.org/trac/ghc/chrome/site/ghc_logo.png
http://ghc.haskell.org/trac/ghc/ticket/8516
Trac 1.0.9simonpjMon, 11 Nov 2013 16:29:05 GMTcc set
http://ghc.haskell.org/trac/ghc/ticket/8516#comment:1
http://ghc.haskell.org/trac/ghc/ticket/8516#comment:1
<ul>
<li><strong>cc</strong>
<em>dreixel</em> added
</li>
</ul>
TicketRyanGlScottWed, 18 Nov 2015 23:35:23 GMT
http://ghc.haskell.org/trac/ghc/ticket/8516#comment:2
http://ghc.haskell.org/trac/ghc/ticket/8516#comment:2
<p>
I really like the idea of adding <tt>(:->:)</tt> to <tt>GHC.Generics</tt>. One of my biggest gripes with <tt>deriving Generic1</tt> is that it doesn't work with many data types that have function arguments (e.g., <tt>Endo</tt>). I think adding <tt>(:->:)</tt> would allow GHC generics to at least be as expressive as <tt>DeriveFunctor</tt>/<tt>Foldable</tt>/<tt>Traversable</tt>.
</p>
<p>
I'm a bit hesitant about adding <tt>Invariant</tt> to <tt>base</tt>, however, primarily because I find it unlikely that it would ever be made a superclass of <tt>Functor</tt>, given the sheer amount of breakage that would cause. Moreover, I don't think we need <tt>Invariant</tt> to be able to derive <tt>Generic1</tt> for data types with <tt>(:->:)</tt>. I believe at most a generated <tt>Generic1</tt> instance would need some <tt>Functor</tt> constraints, but that's no different than the current story.
</p>
<p>
(I haven't worked out the additional rules you'd need to add to the algorithms in Figures 1-4 of <a class="ext-link" href="http://dreixel.net/research/pdf/gdmh.pdf"><span class="icon"></span>http://dreixel.net/research/pdf/gdmh.pdf</a>, but the examples I've worked out by hand so far have only needed <tt>Functor</tt> constraints.)
</p>
Ticket