Deriving Generic1

Ryan Scott ryan.gl.scott at gmail.com
Wed Jun 1 15:21:55 UTC 2016


This is a consequence of the way GHC generics represents datatypes
that compose functor-like types in this fashion. If you compile that
code with -ddump-deriv, you'll see that the Rep1 for Compose is (in
abbreviated form):

    type Rep1 (Compose f g) = ... (f :.: Rec1 g)

where (:.:) is defined as [1]:

    newtype (:.:) (f :: k2 -> *) (g :: k1 -> k2) (p :: k1) = Comp1 (f (g p))

In other words, we must kind-check the type (f (Rec1 g p)). But Rec1
is a datatype, so it must have result kind *. Therefore, the kind of f
is forced to be (* -> *). I describe this in a Note here [2].

This feels like a somewhat fundamental consequence of using datatypes
to abstract over a datatype's structure, so I'm not aware of a way
around this. Luckily, the kind of g is still (k -> *), which was the
main goal of Trac #10604 [3].

Ryan S.
-----
[1] http://git.haskell.org/ghc.git/blob/0676e68cf5fe8696f1f760fef0f35dba14db1104:/libraries/base/GHC/Generics.hs#l865
[2] http://git.haskell.org/ghc.git/blob/0676e68cf5fe8696f1f760fef0f35dba14db1104:/compiler/typecheck/TcGenGenerics.hs#l907
[3] https://ghc.haskell.org/trac/ghc/ticket/10604

On Wed, Jun 1, 2016 at 10:55 AM, Simon Peyton Jones
<simonpj at microsoft.com> wrote:
> Ryan
>
> If you compile
>
> newtype Compose f g a = Compose (f (g a)) deriving( Generic1 )
>
> and do –show-iface on the resulting hi file, you’ll see
>
>   $fGeneric1Compose ::
>
>     forall (f :: * -> *) k (g :: k -> *).
>
>     Functor f =>
>
>     Generic1 (Compose f g)
>
> I was expecting to see
>
>   $fGeneric1Compose ::
>
>     forall (f :: k1 -> *) k (g :: k -> k1).
>
>     (..something..) =>
>
>     Generic1 (Compose f g)
>
> Otherwise the Generic1 instance only works if its first argument has kind (*
> -> *).
>
> Is that the intention?  Maybe so…
>
> Simon


More information about the ghc-devs mailing list