data GenTree f a -- kind (* -> *) -> * -> *
= Node (f (GenTree f a))
| Leaf a
instance Functor f => Functor (GenTree f) where
fmap f (Node ts) = Node (fmap (fmap f) ts)
fmap f (Leaf x) = Leaf (f x)
I don't understand the fmap (fmap f) ts
statement in the above Functor instance. Can somebody explain why it's written this way?
If you look at the structure of Node
it contains an f (GenTree f a)
, so if we look at the types of the expression in question:
fmap f (Node ts) = Node (fmap (fmap f) ts)
f
here is of type a -> b
ts
is of type f (GenTree f a)
, but we should be aware that the f
in this expression is not the function above, but actually the type constructor. In order to get rid of confusion we'll rename the function above to g
as follows:
fmap g (Node ts) = Node (fmap (fmap g) ts)
Now in order to apply our function g
, we'll need to get a hold of an actual value of a
. We know that our f
type constructor has a Functor
instance, so if we map over it we get a GenTree f a
:
fmap (\tree -> ...) ts
Now that we have our GenTree
we can recursively call fmap
on it so that at some point we'll get to the Leaves and actually apply our function to the value, if we wrote this out in all of its boilerplate, it'd look like this:
fmap g (Node ts) = Node (fmap (\tree -> fmap g tree) ts)
So in essence it is written that way, because we need to fmap
over both the f
type constructor and the actual GenTree
.