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

Add documentation for Bimonad #4076

Merged
merged 11 commits into from
Dec 24, 2021
55 changes: 55 additions & 0 deletions docs/src/main/mdoc/typeclasses/bimonad.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
layout: docs
title: "Bimonad"
section: "typeclasses"
source: "core/src/main/scala/cats/Bimonad.scala"
scaladoc: "#cats.Bimonad"
---
# Bimonad

The `Bimonad` trait directly extends `Monad` and `Comonad` without introducing new behaviour. `Bimonad` is
gatear marked this conversation as resolved.
Show resolved Hide resolved
different of other `Bi` typeclasses like `Bifunctor`, `Bifoldable` or `Bitraverse` where the prefix describes a
gatear marked this conversation as resolved.
Show resolved Hide resolved
`F[_, _]`. The `Bimonad` is a `F[_]` and could be better seen as a dual monad i.e. something that is both a `Monad` and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"dual monad" is another one that I worry is confusing. For one, Comonad is not a Monad. Actually it is the dual of Monad!
https://typelevel.org/cats/typeclasses/comonad.html

Copy link
Contributor Author

@gatear gatear Dec 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DualMonad\SelfDualMonad thing i picked from old issues like #1297

I'll change it to:

The `Bimonad` is a `F[_]` and the `Bi` prefix has a different meaning here: it's both a `Monad` and a `Comonad`.

a `Comonad`.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... like this:

Suggested change
Keep in mind `Bimonad` has its own added laws so something that is both monadic
and comonadic may not necessarily be a lawful `Bimonad`.

If you use `Bimonad` as a convenience type such that `def f[T[_] : Monad, Comonad, S](fa: T[S]): S` is re-written to
`def f[T[_] : Bimonad, S](fa: T[S]): S` keep in mind `Bimonad` has its own added laws so something that is both monadic
and comonadic may not necessarily be a lawful `Bimonad`.

###Eval as a Bimonad
Eval is a lawful `Bimonad` so you can chain computations and `extract` the result at the end.
gatear marked this conversation as resolved.
Show resolved Hide resolved

Note the equivalence:
```scala mdoc
import cats._
import cats.data._
import cats.implicits._

Bimonad[Eval].pure(true).extract === Eval.now(true).value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you are trying to show here is that pure is implemented as now and extract as value? One alternative would be to define Bimonad[Eval] here just for demonstrative purposes, WDYT?

Copy link
Contributor Author

@gatear gatear Dec 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you are trying to show here is that pure is implemented as now and extract as value?

Yes

One alternative would be to define Bimonad[Eval] here just for demonstrative purposes, WDYT?

Something like that ?

val evalBimonad = Bimonad[Eval]

evalBimonad.pure(true).extract === Eval.now(true).value

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking like how they define optionMonad in the Monad docs:
http://typelevel.org/cats/typeclasses/monad.html

```

Using generic bimonad syntax we could define a function that appends and extracts a configuration:
```scala mdoc
def make[T[_]: Bimonad](config: T[String]): String =
config
.flatMap(c => Bimonad[T].pure(c + " with option A"))
.flatMap(c => Bimonad[T].pure(c + " with option B"))
.flatMap(c => Bimonad[T].pure(c + " with option C"))
.extract
```

This will work with all types of `Eval`:
```scala mdoc
make(Eval.now("config"))
make(Eval.later("config"))

//String = config with option A with option B with option C
gatear marked this conversation as resolved.
Show resolved Hide resolved
```

Given that `Function0` or `NonEmptyList` are also lawful bimonads the following calls are also valid:
gatear marked this conversation as resolved.
Show resolved Hide resolved
```scala mdoc
make(() => "config")
make(NonEmptyList.one("config"))

//String = config with option A with option B with option C
gatear marked this conversation as resolved.
Show resolved Hide resolved
```
28 changes: 14 additions & 14 deletions docs/src/main/mdoc/typeclasses/typeclasses.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,20 +238,20 @@ From [cats-infographic by @tpolecat](https://github.com/tpolecat/cats-infographi
Originally from [@alexknvl](https://gist.github.com/alexknvl/d63508ddb6a728015ace53cb70a1fd5d)


| Type | Functor | Apply | Applicative | Monad | MonoidK | ApplicativeError | MonadError | CoflatMap | Comonad |
| --------------- |:-------:|:-----------------:|:-----------:|:-----:|:-------:|:-----------------:|:----------:|:---------:|:-------:|
| Id[A] | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✔ |
| Eval[A] | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✔ |
| Option[A] | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ |
| Const[K, A] | ✔ | ✔ (`K:Monoid`) | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
| Either[E, A] | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ |
| List[A] | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✔ | ✗ |
| NonEmptyList[A] | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✔ |
| Stream[A] | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✔ | ✗ |
| Map[K, A] | ✔ | ✔ | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ | ✗ |
| Validated[E, A] | ✔ | ✔ (`E: Semigroup`)| ✔ | ✗ | ✗ | ✔ (`E: Semigroup`)| ✗ | ✗ | ✗ |
| Reader[E, A] | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |
| Writer[E, A] | ✔ | ✔ (`E:Monoid`) | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✗ |
| Type | Functor | Apply | Applicative | Monad | MonoidK | ApplicativeError | MonadError | CoflatMap | Comonad | Bimonad |
| --------------- |:-------:|:-----------------:|:-----------:|:-----:|:-------:|:-----------------:|:----------:|:---------:|:-------:|:-------:|
| Id[A] | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✔ |✔ |
| Eval[A] | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✔ |✔ |
| Option[A] | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ |✗ |
| Const[K, A] | ✔ | ✔ (`K:Monoid`) | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |✗ |
| Either[E, A] | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ |✗ |
| List[A] | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✔ | ✗ |✗ |
| NonEmptyList[A] | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✔ |✔ |
| Stream[A] | ✔ | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✔ | ✗ |✗ |
| Map[K, A] | ✔ | ✔ | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ | ✗ |✗ |
| Validated[E, A] | ✔ | ✔ (`E: Semigroup`)| ✔ | ✗ | ✗ | ✔ (`E: Semigroup`)| ✗ | ✗ | ✗ |✗ |
| Reader[E, A] | ✔ | ✔ | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |✗ |
| Writer[E, A] | ✔ | ✔ (`E:Monoid`) | ✔ | ✔ | ✗ | ✗ | ✗ | ✔ | ✗ |✗ |



Expand Down