简体   繁体   中英

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?

If you look at the structure of Node it contains an f (GenTree fa) , 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 fa) , 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 fa :

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM