Skip to content

Commit

Permalink
Merge pull request #859 from vpavkin/contravariant-docs
Browse files Browse the repository at this point in the history
Add Contravariant documentation page
  • Loading branch information
non committed Feb 3, 2016
2 parents d374a93 + 3495a67 commit cbe3597
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 3 deletions.
78 changes: 78 additions & 0 deletions docs/src/main/tut/contravariant.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
layout: default
title: "Contravariant"
section: "typeclasses"
source: "https://github.com/non/cats/blob/master/core/src/main/scala/cats/functor/Contravariant.scala"
scaladoc: "#cats.functor.Contravariant"
---
# Contravariant

The `Contravariant` type class is for functors that define a `contramap`
function with the following type:

```scala
def contramap[A, B](f: B => A): F[A] => F[B]
```

It looks like regular (also called `Covariant`) [`Functor`](functor.html)'s `map`,
but with the `f` transformation reversed.

Generally speaking, if you have some context `F[A]` for type `A`,
and you can get an `A` value out of a `B` value — `Contravariant` allows you to get the `F[B]` context for `B`.

Examples of `Contravariant` instances are [`Show`](show.html) and `scala.math.Ordering` (along with `algebra.Order`).

## Contravariant instance for Show.

Say we have class `Money` with a `Show` instance, and `Salary` class.

```tut:silent
import cats._
import cats.implicits._
case class Money(amount: Int)
case class Salary(size: Money)
implicit val showMoney: Show[Money] = Show.show(m => s"$$${m.amount}")
```

If we want to show a `Salary` instance, we can just convert it to a `Money` instance and show it instead.

Let's use `Show`'s `Contravariant`:

```tut
implicit val showSalary: Show[Salary] = showMoney.contramap(_.size)
Salary(Money(1000)).show
```

## Contravariant instance for scala.math.Ordering.

`Show` example is trivial and quite far-fetched, let's see how `Contravariant` can help with orderings.

`scala.math.Ordering` typeclass defines comparison operations, e.g. `compare`:

```tut
Ordering.Int.compare(2, 1)
Ordering.Int.compare(1, 2)
```

There's also a method, called `by`, that creates new `Orderings` out of existing ones:

```scala
def by[T, S](f: T => S)(implicit ord: Ordering[S]): Ordering[T]
```

In fact, it is just `contramap`, defined in a slightly different way! We supply `T => S` to receive `F[S] => F[T]` back.

So let's use it in our advantage and get `Ordering[Money]` for free:

```tut
// we need this for `<` to work
import scala.math.Ordered._
implicit val moneyOrdering: Ordering[Money] = Ordering.by(_.amount)
Money(100) < Money(200)
```

6 changes: 3 additions & 3 deletions docs/src/main/tut/invariant.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function with the following type:
def imap[A, B](fa: F[A])(f: A => B)(g: B => A): F[B]
```

Every covariant (as well as contravariant) functor gives rise to an invariant
Every covariant (as well as [contravariant](contravariant.html)) functor gives rise to an invariant
functor, by ignoring the `f` (or in case of contravariance, `g`) function.

Examples for instances of `Invariant` are `Semigroup` and `Monoid`, in
Expand All @@ -29,7 +29,7 @@ timestamp. Let's say that we want to create a `Semigroup[Date]`, by

### Semigroup does not form a covariant functor

If `Semigroup` had an instance for the standard covariant `Functor`
If `Semigroup` had an instance for the standard covariant [`Functor`](functor.html)
typeclass, we could use `map` to apply a function `longToDate`:

```tut:silent
Expand All @@ -47,7 +47,7 @@ like we can't have an `Functor` instance for `Semigroup`.
### Semigroup does not form a contravariant functor

On the other side, if `Semigroup` would form a *contravariant* functor
by having an instance for `Contravariant`, we could make use of
by having an instance for [`Contravariant`](contravariant.html), we could make use of
`contramap` to apply a function `dateToLong`:

```tut:silent
Expand Down

0 comments on commit cbe3597

Please sign in to comment.