4

Compiling this short snippet on GHC 8.6.2:

{-# LANGUAGE DeriveGeneric, PolyKinds #-}
import GHC.Generics

data Foo f
    = FA
    | FB (f (Foo f))
    deriving (Generic, Generic1)

Results in this error:

Can't make a derived instance of ‘Generic1 Foo’:
  Constructor ‘FB’ applies a type to an argument involving the last parameter
                   but the applied type is not of kind * -> *

Is it not possible to derive Generic for such types? Why?

yairchu
  • 23,680
  • 7
  • 69
  • 109

1 Answers1

7

Generic1 Foo can't be derived because Generic1 is meant for types of kind * -> *, not (* -> *) -> *. In principle there could be support for (* -> *) -> * with more constructors in GHC.Generics, but this approach just doesn't scale well (it comes with lots more unintuitive syntactic restrictions, and you will always have the same problem for more complex types).

You can actually do a lot with plain Generic that overlaps with the initially intended use cases for Generic1. Otherwise, you'll need something more powerful than GHC.Generics like, perhaps, the recently released kind-generics (includes links to paper and hackage).

yairchu
  • 23,680
  • 7
  • 69
  • 109
Li-yao Xia
  • 31,896
  • 2
  • 33
  • 56
  • 1
    But the docs say that `Generic1` is for "Representable types of kind `* -> *` (or kind `k -> *`, when `PolyKinds` is enabled)", and I did enable `PolyKinds`! – yairchu Nov 27 '18 at 13:28
  • 3
    There are indeed some higher kinded types for which GHC can currently derive `Generic1` instances, but the feature is so limited it's hardly worth mentioning. This is mostly an artifact of taking the original implementation of `Generic1` intended for `* -> *` (which already has serious limitations), turning on `PolyKinds`, and keeping whatever sticks, which is not much. – Li-yao Xia Nov 27 '18 at 13:42
  • So IIUC the "In principle there could be support for `(* -> *) -> *` with more constructors in `GHC.Generics`" part isn't precise, as the constructor is the right one, it's just that the deriving mechanism doesn't support this kind, right? – yairchu Nov 27 '18 at 15:19
  • 1
    By "constructor" I meant type constructors like `M1`, `(:*:)`, etc. There are missing pieces to be able to define an instance for `Rep1 Foo` even by hand. – Li-yao Xia Nov 27 '18 at 15:35