Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comonad documentation #2888

Merged
merged 5 commits into from
Jun 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
```