Skip to content

Commit

Permalink
Add example of unlawful Applicative for Nested/EitherT
Browse files Browse the repository at this point in the history
  • Loading branch information
kubukoz committed Dec 18, 2018
1 parent 37b7fa7 commit 67ca7b9
Showing 1 changed file with 21 additions and 7 deletions.
28 changes: 21 additions & 7 deletions docs/src/main/tut/guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,19 @@ This rule is relatively flexible. Use what you see appropriate. The goal is to m

### <a id="implicit-priority" href="#implicit-priority"></a> Implicit instance priority

When there are multiple instances provided implicitly, if the type class of them are in the same inheritance hierarchy,
When there are multiple instances provided implicitly, if the type class of them are in the same inheritance hierarchy,
the instances need to be separated out into different abstract class/traits so that they don't conflict with each other. The names of these abstract classes/traits should be numbered with a priority with 0 being the highest priority. The abstract classes/trait
with higher priority inherits from the ones with lower priority. The most specific (whose type class is the lowest in the hierarchy) instance should be placed in the abstract class/ trait with the highest priority. Here is an example.
with higher priority inherits from the ones with lower priority. The most specific (whose type class is the lowest in the hierarchy) instance should be placed in the abstract class/ trait with the highest priority. Here is an example.

```scala
@typeclass
@typeclass
trait Functor[F[_]]

@typeclass
trait Monad[F[_]] extends Functor

...
object Kleisli extends KleisliInstance0
object Kleisli extends KleisliInstance0

abstract class KleisliInstance0 extends KleisliInstance1 {
implicit def catsDataMonadForKleisli[F[_], A]: Monad[Kleisli[F, A, ?]] = ...
Expand All @@ -113,14 +113,28 @@ abstract class KleisliInstance1 {

### Type classes that ONLY define laws.

We can introduce new type classes for the sake of adding laws that don't apply to the parent type class, e.g. `CommutativeSemigroup` and
We can introduce new type classes for the sake of adding laws that don't apply to the parent type class, e.g. `CommutativeSemigroup` and
`CommutativeArrow`.

### <a id="applicative-monad-transformers" href="#applicative-monad-transformers">Applicative instances for monad transformers</a>

We explicitly don't provide an instance of `Applicative` for e.g. `OptionT[F, ?]` given an `Applicative[F]`.
We explicitly don't provide an instance of `Applicative` for e.g. `EitherT[F, String, ?]` given an `Applicative[F]`.
An attempt to construct one without a proper `Monad[F]` instance would be inconsistent in `ap` with the provided `Monad` instance
for `OptionT[F, ?]`. See [#1467](https://github.com/typelevel/cats/issues/1467) for the discussion.
for `EitherT[F, String, ?]`. Such an instance will be derived if you use `Nested` instead:

```scala
import cats._, cats.data._, cats.implicits._

val a = EitherT(List(Left("err"), Right(1)))
val x = (a *> a).value
x: List[Either[String, Int]] = List(Left("err"), Left("err"), Right(1))

val y = (a.toNested *> a.toNested).value
> y: List[Either[String, Int]] = List(Left("err"), Left("err"), Left("err"), Right(1))

x === y
> false
```

#### TODO:

Expand Down

0 comments on commit 67ca7b9

Please sign in to comment.