Search code examples
haskellfunctor

How is this Functor instance implemented?


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?


Solution

  • 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.