-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add comonad first draft * Update menu * Update with Kailuo's suggestion * Couple of corrections
- Loading branch information
1 parent
da2147c
commit a0896a2
Showing
2 changed files
with
90 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
``` |