This post assumes prior knowledge of - the `Functor`

class
/ concept - the functor instance for `Either a`

, ```
(,)
a
```

- basic kind knowledge, e.g. the difference between ```
*
-> *
```

and `* -> * -> *`

## Why

In Haskell, functors can only be defined for types of kind ```
*
-> *
```

like `Maybe a`

or `[a]`

. Their
instances allow us to use `fmap`

(or `<$>`

)
to go from `Maybe a`

to `Maybe b`

using some
`a -> b`

, like:

```
> show <$> Just 1
λJust "1"
> show <$> Nothing
λNothing
> show <$> [1, 2, 3]
λ"1", "2", "3"]
[
> show <$> []
λ []
```

We can even define functor instances for higher kinded types, as long
as we fix type arguments until we get to `* -> *`

. For
example, `Either`

has kind `* -> * -> *`

,
but `Either e`

has kind `* -> *`

. So that means
that we can have a functor instance for `Either e`

, given
some type `e`

. This might sound confusing at first, but all
it means is that the `e`

cannot vary, so we can go from
`Either e a`

to `Either e b`

using some ```
a
-> b
```

, but we cannot go from `Either e1 a`

to
`Either e2 a`

or `Either e2 b`

even if we had both
`a -> b`

and `e1 -> e2`

. How would we even
pass two functions to `fmap`

?

```
> show <$> Right 1
λRight "1"
> show <$> Left True
λLeft True
```

In the first example, we go from `Either a Int`

to
`Either a String`

using ```
show :: Int ->
String
```

. In the second example, we go from ```
Either Bool
a
```

to `Either Bool String`

, where `a`

needs
to have a `Show`

instance.

But what if we want to go from `Either a x`

to
`Either b x`

, given some `a -> b`

?

Let's see how we could implement it ourselves:

```
mapLeft :: (a -> b) -> Either a x -> Either b x
Left a) = Left (f a)
mapLeft f (= r mapLeft _ r
```

Since we are trying to map the `Left`

, the interesting bit
is for that constructor: we apply `f`

under
`Left`

. Otherwise, we just leave the value as-is; a
`Right`

value of type `x`

(we could have written
`mapLeft _ (Right x) = Right x`

and it would work the
same).

Here's a few warm-up exercises. The first uses typed holes to guide
you and clarify what's meant by "using `either`

". The last
exercise can be a bit tricky. Look up what `Const`

is and use
typed holes.

*Exercise 1*: re-implement `mapLeft'`

using
`either`

:

```
mapLeft' :: (a -> b) -> Either a x -> Either b x
= either _leftCase _rightCase e mapLeft' f e
```

*Exercise 2*: implement `mapFirst`

:

`mapFirst :: (a -> b) -> (a, x) -> (b, x)`

*Exercise 3*: implement `remapConst`

:

```
import Data.Functor.Const (Const(..))
remapConst :: (a -> b) -> Const a x -> Const b x
```

## How

While we can implement `mapLeft`

, `mapFirst`

,
and `remapConst`

manually, there is a pattern: some types of
kind `* -> * -> *`

allow both their type arguments to
be mapped like a `Functor`

, so we can define a new class:

```
class Bifunctor p where
{-# MINIMAL bimap | first, second #-}
bimap :: (a -> b) -> (c -> d) -> p a c -> p b d
first :: (a -> b) -> p a c -> p b c
second :: (b -> c) -> p a b -> p a c
```

`bimap`

takes two functions and is able to map both
arguments in a type of kind `* -> * -> *`

.
`first`

is a lot like the functions we just defined manually.
`second`

is always the same thing as `fmap`

. This
class exists in `base`

, under
`Data.Bifunctor`

.

*Exercise 4*: implement `bimap`

in terms of
`first`

and `second`

.

*Exercise 5*: implement `first`

and
`second`

in terms of `bimap`

.

*Exercise 6*: implement the `Bifunctor`

instance
for `Either`

:

```
instance Bifunctor Either where
Left a) = _leftCase
bimap f _ (Right b) = _rightCase bimap _ g (
```

*Exercise 7*: Implement the `Bifunctor`

instance
for tuples `(a, b)`

.

*Exercise 8*: Implement the `Bifunctor`

instance
for `Const`

.

*Exercise 9*: Implement the `Bifunctor`

instance
for `(a, b, c)`

.

*Exercise 10*: Find an example of a type with kind ```
*
-> * -> *
```

that cannot have a `Bifunctor`

instance.

*Exercise 11*: Find an example of a type with kind ```
*
-> * -> *
```

which has a `Functor`

instance when
you fix one type argument, but can't have a `Bifunctor`

instance.