# Understanding contravariance

- 23 minutes (Members only)

In this lesson we learn about the concept of contravariance, contravariant functors, and the `Contravariant`

typeclass defined in the `contravariance`

package.`contravariant`

on Hackage. Note that as of GHC 8.6.1 release, `Data.Functor.Contravariant`

is included in `base`

! The remaining modules from the `contravariant`

package are not in `base`

.

A *functor* in Haskell is a type constructor along with a lawful implementation of the function `fmap`

, the primary method of the `Functor`

typeclass.`Data.Functor`

When given a function, `z0 -> z1`

, and an `f z0`

as inputs, `fmap`

returns an `f z1`

. The `f`

in these types is the type constructor.

This is often referred to as “lifting”, a metaphor for taking something (in this case, a function) from one context to another. We can write the type of `fmap`

with extra parentheses to make the “lifting” more clear:

The function `z0 -> z1`

is transformed into a function `f z0 -> f z1`

, and we say that the function is *lifted into f*.

These are *covariant* functors, although in general we do not talk about them that way until we’ve understood there are also functors with flipped around arguments called *contravariant* functors.

## There are more functors in heaven and Earth

The `Functor`

typeclass provides one basic way to lift, but lifting doesn’t stop there; several other typeclasses provide lifting operations. `Applicative`

, `Monad`

, and `Bifunctor`

can be viewed as `fmap`

with a little something extra. These functors all have lawful implementations of `fmap`

, but not all functors have lawful implementations of the lifting operations from these other classes. There are more functors than there are applicatives; more applicatives than there are monads.

`Contravariant`

and `Profunctor`

, though, are quite different. We’ll just be talking about `Contravariant`

here. After this, you may wish to go on to `Bifunctor`

and `Profunctor`

. Very many functors are covariant functors, while relatively few functors are contravariant.

When you start exploring *contravariant* functors, you may at first think the type of the primary method, `contramap`

, is *contraintuitive*:

Compared to `fmap`

, this seems strange – how do we pass an `a0`

to our `a0 -> a1`

function when what we have is an `f a1`

? How can we transform an `a0 -> a1`

into an `f a1 -> f a0`

? Somehow a result type will need to be adapted into an input type.

The first thing to do in trying to understand `Contravariant`

`Data.Functor.Contravariant`

is to understand what sorts of type constructors are contravariant. Let’s ask the REPL using the `:info`

command: Some output from GHCi has been elided here for brevity.

```
λ> import Data.Functor.Contravariant
λ> :info Contravariant
class Contravariant (f :: * -> *) where
contramap :: (a0 -> a1) -> f a1 -> f a0
instance Contravariant Predicate
instance Contravariant (Op z)
instance Contravariant Equivalence
instance Contravariant Comparison
λ> :info Predicate
newtype Predicate a = Predicate {getPredicate :: a -> Bool}
λ> :info Op
newtype Op z a = Op {getOp :: a -> z}
λ> :info Equivalence
newtype Equivalence a
= Equivalence {getEquivalence :: a -> a -> Bool}
λ> :info Comparison
newtype Comparison a
= Comparison {getComparison :: a -> a -> Ordering}
```

Notice what these types all share: They are all wrappers around *functions*. That narrows the field of what we need to understand considerably!

That’s especially interesting because there is also a *covariant* functor related to functions; that is, there is a lawful `Functor`

instance based on the type constructor `(->)`

. Let’s back up for a moment and see what the covariant functor can teach us.

## A `Functor`

of functions

When you first learn about the `Functor`

class with its definition of `fmap`

, you may have thought of those `f`

types as “containers” For an argument that functors really are containers, see *Functors are Containers* by Bartosz Milewski. or “wrappers” For a more lighthearted take, try *Monads are like burritos* by Mark Dominus. and learned to understand them first as things *like* `Maybe`

and lists. That understanding works fine until you find out about the functor of functions, when suddenly the `f`

is `(a ->)`

and the world shifts just a bit.

Typically when learning Haskell, people learn about function composition before they learn about the `Functor`

typeclass, or perhaps they’ve learned about composition from a math class prior to ever learning Haskell. At any rate, it is often a surprise for people to learn that function composition is the `fmap`

of functions, or, more precisely for the type constructor `((->) a)`

. Let’s take a moment to understand why this is so.

As we said above, functors lift a function `z0 -> z1`

to a function `f z0 -> f z1`

where `f`

is some type constructor. The type constructor for functions looks like this (simplified a bit):

It’s a special datatype, and yet for the purposes of talking about the `Functor`

instance, it works similarly to a pair or two-tuple type. As usual for type constructors with more than one type parameter, we must partially apply this constructor to write the instance.

Note that `(->) a`

is equivalent to `(a ->)`

.

We’ve already said that this implementation of `fmap`

is the same as `(.)`

, but we want to prove it to ourselves.

Recall the general type of `fmap`

:

We know the `f`

here will be `(->) a`

, so `f z0`

is `((->) a) z0`

and `f z1`

is `((->) a) z1`

. Thus our `fmap`

specialized to `(->) a`

looks like this:

We can rewrite that with the arrows in infix notation as

Let’s compare that directly to the type of function composition:`Data.Function`

If we label the `(->) a`

type constructor `f`

, then we see how we get directly from the type of composition to the type of `fmap`

.

Thus we can finish our `fmap`

implementation by defining it as function composition.

We can think of this as lifting a function into a context of another function. Lifting a function into a function context provides a context in which it can accept as input the output of another function. If we have a function `f :: a -> z0`

but we need a function `a -> z1`

, then a function `g :: z0 -> z1`

takes us there via `fmap g`

. When we lift `g`

into the context of `(a ->)`

via `fmap g`

, we adapt `f`

from `a -> z0`

to `a -> z1`

by post-processing its result.

To put another way: The type constructor `(->) a z`

is covariant in its second argument.

## Contravariant composition

Now it’s time for something completely different.

Contravariant functors reverse the direction of composition.

Covariance and contravarianceon Wikipedia

This gives us a good place to begin our investigation into contravariance – by writing a reversed function composition.

We want to write a “contra-composition” function that compares to regular (covariant) composition like this:

The implementations also resemble each other.

We can see that the only difference here is that it we have flipped the order of the arguments. And if we experiment with these in the REPL, we would get the expected results:

This isn’t a super compelling example; why would you particularly *want* to flip the application order around like this? We’ll ask you to defer judgment on that question until we can get to some more interesting examples in a bit.

But the upshot is:

- If we have a function
`a -> z0`

and we need`a -> z1`

then we need to change our*result*types, so we need an “adaptor” function`z0 -> z1`

to get there. - If we have a function
`a0 -> z`

and we need`a1 -> z`

, we have to change the*input*type. We need a function from`a1 -> a0`

to get there.

With covariant composition, we wanted to change the *result* type and did so by passing it to an adaptor function. Now we want to change the input type by pre-processing the input before passing it off to our original function.

Contrasting `Functor`

versus `Contravariant`

, we can see this by annotating the composition types like this:

With covariant right-to-left function composition, the `f`

constructor represents fixing the type of the function’s *input*. With the contravariant, left-to-right functor of functions, the `f'`

constructor represents fixing the type of the function’s *result.*

By “fixing”, we mean a shorthand for it being a free, or unbound, variable. For example, if we say, “consider `Either a b`

where `a`

is fixed”, we mean “consider `\b -> Either a b`

.” The `a`

is arbitrary, but for the purposes of the discussion it’s not the input variable for the functor – `b`

is the input variable for the functor. So when we say that `(->) a b`

is covariant in its second argument and *fixes* the type of the input, we’re saying that, whatever the type of `a`

, it isn’t the object of our concern; we’re not going to touch it or transform it or adapt it. It’s a black box as far as our composition is concerned.

## On to `Contravariant`

What we just did above is a good gateway to understanding the `Contravariant`

class and its `contramap`

method, because `contramap`

is exactly the flipped composition that we just wrote!

That last instance doesn’t actually compile, unfortunately. We need to wrap the function type in a newtype with the type arguments ordered so that we can fix `z`

and write the `Contravariant`

instance with `a`

as the bound type variable.

We have various choices for newtypes, but the most basic is `Op.`

`Op`

is a wrapper around a function with its arguments flipped:

Let’s talk about this declaration for a moment. `Op`

has two parameters; when we look at the data constructor, we see that the first parameter is the *result* of a function, and the second parameter is the *input*. The `getOp`

function allows us to conveniently unwrap an `Op`

value into this underlying function: given an `Op z a`

value as its first argument, it gives us a function `a -> z`

.

`Op`

Let’s rewrite our `contraComp`

example from above, but using `Op`

.`Op`

The `contramap`

definition for `Op`

should look familiar, with a bit of extra plumbing:

Compare this to our previous definition of flipped function composition, `contraComp`

:

Or, equivalently:

Let’s see if we can turn our completely contrived `length`

example from above into a fancy `contramap`

example. We want to check lists to see if they are of length 10:

```
isTen :: Op Bool Int
isTen = Op (== 10)
isListOfTen :: Op Bool [a]
isListOfTen = contramap length isTen
```

Notice that because `Op`

has its parameters in the reverse order of the wrapped function, the `Bool`

*results* are the first type argument, while the inputs are the second type argument. `isListOfTen`

takes a list as its input, while `isTen`

takes an `Int`

as input; each returns a `Bool`

.

Remember that `contramap length isTen`

is equivalent to `(getOp isTen) . length`

.

In the REPL:

`Predicate`

What we just wrote using `Op Bool`

is perhaps better captured by the newtype `Predicate`

,`Predicate`

which is a wrapper around `a -> Bool`

functions.

Let’s refactor to use `Predicate`

and its `contramap`

:

```
isTen :: Predicate Int
isTen = Predicate (== 10)
isListOfTen :: Predicate [a]
isListOfTen = contramap length isTen
```

Use `getPredicate`

to apply this to a list and run it:

Let’s add an additional function to filter a list of lists with our predicate:

`Equivalence`

Another contravariant functor worth looking at is `Equivalence`

.`Equivalence`

`Equivalence`

is a newtype wrapper around equality relations.

The `contravariant`

package also provides a function called `defaultEquivalence`

that puts `==`

into the `Equivalence`

context, much the way our `isTen`

functions above put `(== 10)`

into the `Op`

or `Predicate`

context.

Now we can use this to check for equivalence on only one side of a tuple by contramapping

```
fstEquivalence :: Eq a => Equivalence (a, b)
fstEquivalence =
contramap fst defaultEquivalence
sndEquivalence :: Eq b => Equivalence (a, b)
sndEquivalence =
contramap snd defaultEquivalence
```

If we compare two tuples using a default equivalence, it checks both elements for equality:

```
λ> getEquivalence defaultEquivalence (1, 2) (1, 3)
False
λ> getEquivalence defaultEquivalence (1, 2) (1, 2)
True
```

But using the equivalences we wrote above, we can also compare them on just one side or the other:

```
λ> getEquivalence fstEquivalence (1, 2) (1, 3)
True
λ> getEquivalence sndEquivalence (1, 2) (1, 3)
False
```

In summary, for covariant functors, the unlifted and lifted functions point in the same direction, `z0 -> z1`

. With contravariance, the unlifted and lifted functions point in opposite directions: one goes `a0 -> a1`

, the other goes `a1 -> a0`

, but reversing the order of composition lets us get where we need to go.

## What’s next

While you can imagine functions like this, that filter some inputs by one or more predicates, all of this could have been written another way. You may have even invented flipped function composition on your own without realizing it had a name! But contravariance really starts to shine in the context of bifunctors. Bifunctors that are contravariant in their first argument and covariant in their second argument are called *profunctors*.