Skip to content

Commit

Permalink
Comonad documentation (#2888)
Browse files Browse the repository at this point in the history
* Add comonad first draft

* Update menu

* Update with Kailuo's suggestion

* Couple of corrections
  • Loading branch information
justinhj authored and kailuowang committed Jun 24, 2019
1 parent da2147c commit a0896a2
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 0 deletions.
5 changes: 5 additions & 0 deletions docs/src/main/resources/microsite/data/menu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ options:
menu_type: typeclasses
menu_section: monads

- title: Comonads
url: typeclasses/comonad.html
menu_type: typeclasses
menu_section: comonads

- title: Variance and Functors
url: typeclasses/functor.html
menu_type: typeclasses
Expand Down
85 changes: 85 additions & 0 deletions docs/src/main/tut/typeclasses/comonad.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
layout: docs
title: "Comonad"
section: "typeclasses"
source: "core/src/main/scala/cats/Comonad.scala"
scaladoc: "#cats.Comonad"
---
# Comonad

`Comonad` is a `Functor` and provides duals of the [`Monad`](monad.html) `pure`
and `flatMap` functions. A dual to a function has the same types but the
direction of the arrows are reversed. Whether or not that is useful even possible
depends on the particular type. For a more formal definition of duality, please
refer to [https://ncatlab.org/nlab/show/duality](https://ncatlab.org/nlab/show/duality).

### extract

Monad's have `pure` from `Applicative` which gives you the ability to wrap
a value `A` using the type constructor giving an `F[A]`. Comonad has
`extract` which instead takes an `F[A]` and extracts the `A`. Therefore, to be
able to implement extract we must have a type of which we are certain
we can get an `A` from an `F[A]`. For example we cannot always get an `A`
from a `List[A]` because if the list is empty there is nothing to get.

For the same reason, `Option` doesn't have a Comand instance, because we
cannot always get an `A` from an Option, it may be empty too.

Some examples that we can implement `Comonad` for include `OneAnd`, `Tuple2`
and the "non empty" collections.

First some imports.

```tut:silent
import cats._
import cats.data._
import cats.implicits._
import cats.syntax.comonad._
import cats.instances.list._
```

`NonEmptyList` has a `Comonad` instance and its implementation of `extract`
simply returns the head element of the list, which we know we will always
have.

```tut:book
NonEmptyList.of(1,2,3).extract
```

### coflatMap

`coflatMap` is the dual of Monad's `flatMap`. While `flatMap` allows us to chain
together operations in a monadic context, `coflatMap` takes a value in some context
`F[A]` and a function `F[A] => B` and returns a new value in a context `F[B]`.

The default implementation of `coflatMap` for `NonEmptyList` will pass the supplied
function with the whole list, then the tail of that, then the tail of that and so
on. This is illustrated below.

```tut:book
NonEmptyList.of(1,2,3,4,5).coflatMap(identity)
```

# CoflatMap

While `FlatMap` is a weaker version of `Monad` that doesn't have the `pure` function,
`CoflatMap` is a `Comonad` without the `extract` function. There are many instances
of type classes in Cats that implement `CoflatMap` but not `Comonad`.

For example we cannot write `extract` for `Option[A]` because there's no way to
pull an `A` out of nowhere if the Option is empty.

```tut:silent
def extract[A](fa : Option[A]): A = fa match {
case Some(a) => a
case None => ??? // What now?
}
```

Another example is `List`. Remember we cannot write `extract` for list because lists
can be empty, but we can implement the `coflatMap` and it works identically to the
one shown above for `NonEmptyList`.

```tut:book
List(1,2,3,4,5).coflatMap(identity)
```

0 comments on commit a0896a2

Please sign in to comment.