The compiler error here is helpful, but only in that annoying way where it tells you exactly what is wrong but not why it is wrong.
Expected a type but "Rep a" has kind "* -> *".
So the problem here is that Rep (a type family) needs two arguments (call them a and p, as in Rep a p); it as a type-level function maps these two type arguments into the "generic" type. For example,
data Empty deriving Generic
instance Generic Empty where
type Rep Empty =
D1 ('MetaData "Empty" "Main" "package-name" 'False) V1
-- taken from https://hackage.haskell.org/package/base-4.9.0.0/docs/GHC-Generics.htm
a, e.g. Empty, represents the type from which we are genericizing.
p is a dummy type so that we can reuse our representation types for higher-level types (see Generic1 in the documentation).
So, in the above example, Rep Empty p would simplify to D1 ('MetaData ...) V1 p.
We can usually ignore p except when it comes to defining new typeclasses that take advantage of generics. We want to pattern match on on types like D1 ('MetaData ...) V1 p but we need some way of handling the extra parameter.
A trick then is to treat D1 ('MetaData ...) V1 like a higher-level type (like a functor). This is our f in GDefault.
class GDefault f where
gdef :: f a
Yes a will always be this stupid parameter that we will never use, but in return for line noise we get the ability to pattern match on the f in our instances. Here are four instances that allow for automatic generic def implementations for product types (:*: being a lifted tuple):
instance GDefault U1 where
gdef = U1
instance Default a => GDefault (K1 i a) where
gdef = K1 def
instance (GDefault a, GDefault b) => GDefault (a :*: b) where
gdef = gdef :*: gdef
instance GDefault a => GDefault (M1 i c a) where
gdef = M1 gdef
This, along with some sensible defaults for the numeric tower, will let us define datatypes like data Foo = Foo Int Char Float deriving (Show, Generic) and evaluate show (def :: Foo) to "Foo 0 0 0.0".
Your code had gdef :: a, which is the wrong kind. We want gdef :: f a because the typeclass is defined on types with kind * -> *, hence the error message.
And to take advantage of this helper class, we do much as you did:
class Default a where
def :: a
default def :: (Generic a, GDefault (Rep a)) => a
def = to gdef
to :: Rep a x -> a introduces a spurious x, which unifies with our gdef :: f a to produce f ~ Rep a, throwing away the x and being exactly what we intended.
You can see this approach elaborated in the data-default package.
fto have kind* -> *(since it uses it asf a) but your class argumenta(ofGDefault) expects only a type (so kind*), but you are still feeding it something of kind* -> *. – Alec Sep 21 '16 at 14:53