﻿

The Functor class

## Contents

This chapter serves a dual role. In it, we will not only introduce the very important `Functor` class but also use it as a simple example of how type classes can be useful tools for solving problems in a more general way.

## Motivation

In Other data structures, we have seen how apply-to-all-elements operations (of which `map` is the prime example) are not specific to lists. One of the examples we worked through was that of the following tree datatype:

```data Tree a = Leaf a | Branch (Tree a) (Tree a) deriving (Show)
```

The map function we wrote for it was:

```treeMap :: (a -> b) -> Tree a -> Tree b
treeMap f (Leaf x) = Leaf (f x)
treeMap f (Branch left right) = Branch (treeMap f left) (treeMap f right)
```

Later in that chapter we also defined "maps" for `Weird` and (in a passage of the final example) `Maybe`; and could conceivably do the same for any arbitrary data structure.

The list-based `map` makes the apply-to-all-elements strategy general with regards to the function being applied[1]. Now, we can see that a further generalization is possible: mapping over types other than lists. Type classes provide a way of expressing this generality.

## Introducing Functor

`Functor` is a Prelude class for types which can be mapped over. It has a single method, called `fmap`. The class is defined as follows:

```class  Functor f  where
fmap        :: (a -> b) -> f a -> f b
```

The usage of the type variable `f` can look a little strange at first. Here, `f` is a parametrized data type; in the signature of `fmap`, it takes `a` as a type parameter in one of its appearances and `b` in the other. It becomes easier to see what is going on by considering an instance of `Functor` - say, `Maybe`. By replacing `f` with `Maybe` we get the following signature for `fmap`...

```fmap        :: (a -> b) -> Maybe a -> Maybe b
```

... which fits the natural definition:

```instance  Functor Maybe  where
fmap f Nothing    =  Nothing
fmap f (Just x)   =  Just (f x)
```

(Incidentally, this definition is in Prelude; and thus we didn't really need to have implemented `maybeMap` for that example in "Other data structures".)

Unsurprisingly, the `Functor` instance for lists (also in Prelude) is just...

```instance  Functor []  where
fmap = map
```

... and replacing `f` for `[]` in the `fmap` signature gives us the familiar type of `map`.

Summing it all up, we can say that `fmap` is a generalization of `map` for any parametrized data type[2].

Naturally, we can provide `Functor` instances for our own data types. In particular, `treeMap` can be promptly relocated to an instance:

```instance  Functor Tree  where
fmap f (Leaf x) = Leaf (f x)
fmap f (Branch left right) = Branch (fmap f left) (fmap f right)
```

To close this first stretch, a quick demo of `fmap` in action with the instances above (to reproduce it, you only need to load the `data` and `instance` declarations for `Tree`; the others are already in Prelude):

```*Main> fmap (2*) [1,2,3,4]
[2,4,6,8]
*Main> fmap (2*) (Just 1)
Just 2
*Main> fmap (fmap (2*)) [Just 1, Just 2, Just 3, Nothing]
[Just 2,Just 4,Just 6,Nothing]
*Main> fmap (2*) (Branch (Branch (Leaf 1) (Leaf 2)) (Branch (Leaf 3) (Leaf 4)))
Branch (Branch (Leaf 2) (Leaf 4)) (Branch (Leaf 6) (Leaf 8))
```

Note

Beyond the `[]` and `Maybe` examples mentioned here Prelude provides a number of other handy `Functor` instances. The full list can be found in GHC's documentation for the Control.Monad module.

### The functor laws

When providing a new instance of `Functor`, you should ensure it satisfies the two functor laws. There is nothing mysterious about these laws; their role is to guarantee `fmap` behaves sanely and actually performs a mapping operation (as opposed to some other nonsense). Indeed, a type whose `Functor` instance does not obey the functor laws cannot properly be called a functor[3]. The first law is:

```fmap id  ==  id
```

`id` is the identity function, which returns its argument unaltered. The first law states that mapping `id` over a functor must return the functor unchanged.

Next, the second law:

```fmap (f . g)  ==  fmap f . fmap g
```

It states that it should not matter whether we map a composed function or first map one function and then the other (assuming the application order remains the same in both cases).

## What did we gain?

At this point, we can ask what benefit we get from the extra layer of generalization brought by the `Functor` class. There are two significant advantages:

• Starting from the more superficial one, the availability of the `fmap` method relieves us from having to recall, read and write a plethora of differently named mapping methods (`maybeMap`, `treeMap`, `weirdMap`, ad infinitum). As a consequence, code becomes both cleaner and easier to understand - on spotting a use of `fmap` we instantly have a general idea of what is going on[4].
• More significant, however, is the ability, granted by the type class system, to write `fmap`-based algorithms which work out of the box with any functor - be it `[]`, `Maybe`, `Tree` or whichever you need. Indeed, a number of useful classes in the hierarchical libraries inherit from `Functor`[5].

Type classes make it possible to create general solutions to whole categories of problems. While it is possible that, depending on what you will use Haskell for, you will not need to define new classes often, it is sure that you will be using type classes all the time. Many of the most powerful features and sophisticated capabilities of Haskell rely on type classes residing either in the standard libraries or elsewhere. And of course, classes will be a permanent presence in this book from this point on - beginning with the all-important `Monad`.

## Notes

1. Such generalization was one of the main themes of More about lists.
2. Data structures provide the most intuitive examples; however, there are functors which cannot reasonably be seen as data structures. A commonplace metaphor consists in thinking of functors as containers; like all metaphors, however, it can be stretched only so far.
3. The functor laws, and indeed the concept of a functor, are grounded on a branch of Mathematics called Category Theory. That need not be a concern for you at this point; in any case, we will have opportunities to explore related topics in the Advanced Track of this book.
4. The situation is analogous to the gain in clarity provided by replacing explicit recursive algorithms on lists with implementations based on higher-order functions.
5. Note for the curious: For one example, have a peek at Applicative Functors in the Advanced Track (for the moment you can ignore the references to monads there).

 The Functor class Intermediate Haskell Modules  >> Standalone programs  >> Indentation  >> More on datatypes  >> Other data structures  >> Classes and types  >> The Functor class edit this chapter Haskell edit book structure