Lecture 5 (2018-01-30)
Functor
We talked about the `Functor` type class, defined as:
```Haskell
class Functor f where
fmap :: (a -> b) -> f a -> f b
-- LAW: fmap id = id
```
When you see `Functor`, think "Mappable": a type with a `Functor`
instance is one that can be mapped over, i.e., you can change all of
the values in the holes while preserving the structure.
Our first example was lists, which was easy: we already know the `map`
function well!
```Haskell
instance Functor ([]) where
fmap = map
```
We defined a separate type, `Box`, to see how far we could go:
> data Box a = B a deriving Show
>
> instance Functor Box where
> fmap f (B v) = B (f v)
We saw how to do it for `Maybe`, too:
```Haskell
instance Functor Maybe where
fmap f Nothing = Nothing
fmap f (Just v) = Just (f v)
```
We carefully preserve the structure of our argument: if we're given a
`Nothing`, the types themselves force us to return a `Nothing`. If
we're given `Just v`, we *could* return `Nothing`, but then we'd
violate the `Functor` law that mapping with the identity is the
identity.
We also defined 'readers', that is, functions whose domain is some
fixed type `r`. Readers disrupt our notion of interpreting functorial
type constructors of kind `* -> *` as mere 'containers', that is,
things that might hold some value. Readers are functions---there's no
way to rip open and get the value out of a function. We'll have to
broaden our intuition---that functors are 'computational contexts'
that will *produce* a value---perhaps by containing one, perhaps by
other means.
In any case, to figure out the instance for `(->) r`, we let types be
our guide.
```Haskell
instance Functor ((->) r) where
-- fmap :: (a -> b) -> ((->) r a) -> ((->) r b)
-- i.e. (a -> b) -> (r -> a) -> (r -> b)
fmap fab fra = \r -> fab (fra r)
```
We didn't define an instance for an `Either` type, but here's the one
Haskell gives you: the first parameter is fixed, just like readers. Note that
`Either :: * -> * -> *` but for a type `e`, we have `Either e :: * ->
*`---which is exactly the kind of thing that can be a `Functor`.
```Haskell
instance Functor (Either e) where
fmap f (Left err) = Left err
fmap f (Right v) = Right (f v)
```
You'll notice I used the suggestive name `err` for the left-hand
side. Haskell uses the `Either` type to talk about computations that
*could* fail: if an error occurs, we return a `Left`; if we succeed,
we return a `Right`. Don't worry: this choice has more to do the
synonymy of "right" and "correct" than politics.