# Learn Contravariant in 5 minutes

## Functor

Early into learning Haskell, we’re introduced to the `Functor`

typeclass and
how to `fmap`

our way around with it. `fmap`

is a structure-preserving operation
that lets us transform the value wrapped by the structure:

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

`Maybe`

has a `Functor`

instance:

```
maybeFunctor :: Maybe Int -> Maybe String
maybeFunctor mInt = fmap show mInt
```

`[]`

also has a `Functor`

instance:

```
listFunctor :: [Int] -> [String]
listFunctor xs = fmap show xs
```

Even the function arrow has a `Functor`

instance, when the type on the left-hand
side of the arrow is fixed:

```
functionFunctor :: (a -> Int) -> (a -> String)
functionFunctor f = fmap show f -- a.k.a. (show . f)
```

A loosey-goosey intuition is that `fmap`

lets us map over the *output* of a
computation.

## Contravariant

There is another “mapping” typeclass out there - `Contravariant`

- that we
likely don’t bump into as often as `Functor`

:

```
class Contravariant f where
contramap :: (b -> a) -> f a -> f b
```

On first blush, if we look at `Contravariant`

with the more familiar `Functor`

as our frame of reference, `contramap`

’s type signature can be very puzzling.
How can we apply a function with type `(b -> a)`

to the guts of an `f a`

structure?

A challenge we might face here is that considering we’re likely so used to
common structures that have `Functor`

instances, we may first try substituting
in those same structures for `f`

, e.g. `Maybe`

, `[]`

, and so on. GHC will
quickly tell us that there are no `Contravariant`

instances for these
structures, so at this point, we’ll need to look at `Contravariant`

from a new
angle.

Let’s look at a concrete example:

```
import Control.Exception.Safe (SomeException(SomeException), catch)
import Control.Monad (void)
import Data.Aeson (encode)
import Data.Text (Text)
import Network.HTTP.Client
( RequestBody(RequestBodyLBS), Manager, httpNoBody, parseUrlThrow, requestBody
)
newtype Processor a = Processor
{ runProcessor :: a -> IO ()
}
type LogMessage = Text
batchLogProcessor :: Manager -> Processor [LogMessage]
batchLogProcessor manager =
Processor
{ runProcessor = \logs -> do
let requestBody = RequestBodyLBS $ encode logs
req <- parseUrlThrow "POST http://my-log-aggregation-service.org/post"
void (flip httpNoBody manager req { requestBody })
`catch` \(SomeException ex) -> do
-- ... do something with the exception here ...
}
```

The `Processor`

type wraps a function that takes in as input some value, and
then does something with that value in `IO`

. We built a `batchLogProcessor`

that lets us send a batch of logs up to some log aggregation service.

We can also define a convenient (albeit less performant) `Processor`

that just
sends up one log message at a time, rather than sending a batch. We’ll implement
this one in terms of `batchLogProcessor`

:

```
singletonLogProcessor :: Manager -> Processor LogMessage
singletonLogProcessor manager =
Processor
{ runProcessor = \logMsg -> do
runProcessor (batchLogProcessor manager) [logMsg]
}
```

This type of operation - mapping over the *input* - is really the essence of
`Contravariant`

. We can define a `Contravariant`

instance for `Processor`

:

```
instance Contravariant Processor where
contramap :: (b -> a) -> Processor a -> Processor b
contramap f inputProcessor =
Processor
{ runProcessor = \x -> do
runProcessor inputProcessor $ f x
}
```

With a `Contravariant`

instance, we can now define `singletonLogProcessor`

using
`contramap`

:

```
singletonLogProcessor :: Manager -> Processor LogMessage
singletonLogProcessor manager =
contramap (\logMsg -> [logMsg]) $ batchLogProcessor manager
```

We’re also free to `contramap`

to our heart’s content on all sorts of
`Processor`

s, not just ones specific to log aggregation.