Reputation: 1
I've been going through the GHC Generics documentation here and it seems the example code is incorrect. The part I have trouble with is this:
type RepUserTree a =
-- A UserTree is either a Leaf, which has no arguments
U1
-- ... or it is a Node, which has three arguments that we put in a product
:+: a :*: UserTree a :*: UserTree a
given that the the (:*:)
type operator is defined as data (:*:) f g p = f p :*: g p
, as expected, the above bit of code gives the kind error:
Blockquotetest.hs:26:13: error:
• Expecting one fewer argument to ‘UserTree a’
Expected kind ‘* -> *’, but ‘UserTree a’ has kind ‘*’
• In the first argument of ‘:*:’, namely ‘UserTree a’
In the second argument of ‘:*:’, namely ‘UserTree a :*: UserTree a’
In the second argument of ‘:+:’, namely
‘a :*: (UserTree a :*: UserTree a)’
Is the documentation incorrect? Am I missing an extension that makes the above work? I'm not really sure how to go about changing the above to compile.
Upvotes: 0
Views: 55
Reputation: 2214
It is just a dummy example to give you an idea of what it is doing because the details are a bit more complex. But it might be worth understanding why it doesn't compile because it is good to understand what is going wrong in these situations if you want to do any sort of type level programming in Haskell.
If you look at the type parameters of (:+:)
and (:*:)
, you can see that they each take three types, f g p
. They are both kind * -> * -> * -> *
.
data (:+:) f g p = L1 (f p) | R1 (g p)
data (:*:) f g p = f p :*: g p
and p
is given to f
and g
, so we know that f
and g
must be at least kind * -> *
. The UserTree
type's kind is * -> *
.
data UserTree a = Node a (UserTree a) (UserTree a) | Leaf
but in the declaration we have UserTree a
, which is of kind *
whereas what (:*:) is expecting two things of at least kind * -> *
.
type RepUserTree a = U1 :+: a :*: UserTree a :*: UserTree a
If you remove the a
you get it to compile.
type RepUserTree a = U1 :+: a :*: UserTree :*: UserTree
Now look at U1
, K1
and M1
they all end in the p
parameter. Notice that in the RealRepUserTree
example, U1
, K1
and M1
all take one type less they than can. These meets the requirements of both (:+:)
and (:*:)
.
Upvotes: 0