I was recently started reading Thinking with Types and came upon a great explanation of variance and the role it plays in reasoning about functions.
You’re probably familiar with `Functor`

, which says that for some `t a`

, if given a function `f :: a -> b`

, you can transform the `t a -> t b`

. Essentially, the essence of “functor-ness” is the ability to transform a result into another type.
What about “anti-functorn-ness”, where you want to transform the input rather than the result of a function from `a -> b`

? Is that something interesting and worth exploring?

Indeed it is! The “functor-ness” described above is actually called `Covariance`

, and simply means that you can transform the output of some computation `T a`

.
Similarly, the “anti-functor-ness” of `T a`

is called `Contravariance`

, and means that you can transform a `T b`

into a `T a`

by mapping the input of the computation. There is a third form of variance called `Invariance`

, but its not as much fun as co & contra variance.

Type variables in an expression are either positive or negative. In the function `a -> b`

, the `b`

is positive, while the `a`

is negative. Just like integer mathematics, two negatives make a positive, so `(a -> b) -> b`

actually has `a`

in positive position, meaning this covariant in `a`

.
In fact, whether a `T a`

is co or contra variant in `a`

is determined only by whether `a`

is positive or negative. Positive `a`

means `Covariance`

, while negative `a`

means `Contravariance`

. If the `a`

appears in both positive and negative positions, then its invariant, and therefore not particularly exciting.

Now that we have a few types of variance, lets use them to reason about whether or not some type signatures are `Functor`

s in `a`

or not.

```
foo :: a -> b
bar :: b -> a
baz :: (b -> a) -> b
fiz :: (a -> b) -> b
```

In `foo`

, `a`

is the input rather than output, and since we’ve already established that `Functor`

s transform the output, `foo`

may not be a functor. To confirm this intuition, we can use our newfound knowledge about variance & notice that `a`

occurs in negative position. Since `Functor`

relies on the type being covariant in `a`

, and covariance is determined by a positive `a`

, we can be certain that `foo`

is contravariant and therefore not a `Functor`

. By the same reasoning, we can be certain that `bar`

, where `a`

occurs in positive position, is a `Functor`

. `baz`

is an interesting case because `a`

occurs in positive position in the argument function, but the argument function occurs in negative position. Just like basic arithmetic, a positive multiplied by a negative is a negative, so `baz`

is contravariant in `a`

and not a `Functor`

. Again, using the same logic, by flipping the position of `a`

in the argument function to negative position & creating a double negative, `a`

occurs in positive position in `fiz`

. So `fiz`

is a `Functor`

.

I’ll dive deeper into how `(a -> b) -> b`

manifests itself as JavaScript style continuations in my next post.