Functors in Haskell. Adapted from material by Miran Lipovaca. Functors. Functors are a typeclass, just like Ord, Eq, Show, and all the others. This one is designed to hold things that can be mapped over; for example, lists are part of this typeclass. class Functor f where
Adapted from material by Miran Lipovaca
Functors are a typeclass, just like Ord, Eq, Show, and all the others. This one is designed to hold things that can be mapped over; for example, lists are part of this typeclass.
Only one typeclass method, called fmap. Basically, says: give me a function that takes a and returns b and a “box” with type a inside of it, and I’ll return a “box” with type b inside of it.
map :: (a -> b) -> [a] -> [b]
So map is a lot like a functor! Here, map takes a function and a list of type a, and returns a list of type b.
In fact, can define map in terms of fmap:
We did NOT write “instance Functor [a] where…”, since f has to be a type constructor that takes one type.
Here, [a] is already a concrete type, while  is a type constructor that takes one type and can produce many types, like [Int], [String], [[Int]], etc.
Again, we did NOT write “instance Functor (Maybe m) where…”, since functor wants a type constructor.
Mentally replace the f’s with Maybe, so fmap acts like (a -> b) -> Maybe a -> Maybe b.
If we put (Maybe m), would have (a -> b) -> (Maybe m) a -> (Maybe m) b, which looks wrong.
This is slightly different than our last definition. Here, trees will be of the form:
Node 5 (Node 3 (Node 1 EmptyTree EmptyTree) (Node 4 EmptyTree EmptyTree)) (Node 6 EmptyTree EmptyTree)
Note: we deliberately assumed we could compare the elements of the nodes so that we could make this a binary search tree.
If this is an “unordered” tree, would need to search both left and right subtrees.
If we looked at fmap as though it were only for trees, it would look something like:
(a -> b) -> Tree a -> Tree b
We can certainly phrase this as a functor, also:
For this situation, we need to partially apply the type constructor until it takes only 1 input.
Remember, Haskell is good at partial evaluations!
instance Functor (Either a) where
fmap :: (b -> c) -> Either a b -> Either a c
There are two rules that every functor should obey. Note that these aren’t enforced by Haskell, but they are important!
First: If we map the identity function over a functor, then the functor we get back should be the same as the original functor. So: fmap id = id.
Second rule: composing two functions and then mapping the resulting function over a functor should be the same as first mapping one function over the functor and then mapping the other. So:
fmap (f . g) = fmap f . fmap g.
Huh? Well, fmap (f . g) (Just x) is (if you go back and look) defined as Just ((f . g) x), which is the same as Just (f (g x)), since we’re just composing functions.
And fmap f (fmap g (Just x)) is fmap f (Just (g x)) which is then Just (f (g x)), so we’re ok!