-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Cats-1567 Replace Split with Commutative Arrow. Introduces Commutative Monad. #1719
Changes from all commits
d14202f
e59a0e0
5380fa3
0fd9a0f
670955a
56efbec
b8f0658
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package cats | ||
|
||
import simulacrum.typeclass | ||
|
||
/** | ||
* Commutative CoflatMap. | ||
* | ||
* Further than a CoflatMap, which just allows composition of dependent effectful functions, | ||
* in a Commutative CoflatMap those functions can be composed in any order, which guarantees | ||
* that their effects do not interfere. | ||
* | ||
* Must obey the laws defined in cats.laws.CommutativeCoflatMapLaws. | ||
*/ | ||
@typeclass trait CommutativeCoflatMap[F[_]] extends CoflatMap[F] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package cats | ||
|
||
import simulacrum.typeclass | ||
|
||
/** | ||
* Commutative Comonad. | ||
* | ||
* Further than a Comonad, which just allows composition of dependent effectful functions, | ||
* in a Commutative Comonad those functions can be composed in any order, which guarantees | ||
* that their effects do not interfere. | ||
* | ||
* Must obey the laws defined in cats.laws.CommutativeComonadLaws. | ||
*/ | ||
@typeclass trait CommutativeComonad[F[_]] extends Comonad[F] with CommutativeCoflatMap[F] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package cats | ||
|
||
import simulacrum.typeclass | ||
|
||
/** | ||
* Commutative FlatMap. | ||
* | ||
* Further than a FlatMap, which just allows composition of dependent effectful functions, | ||
* in a Commutative FlatMap those functions can be composed in any order, which guarantees | ||
* that their effects do not interfere. | ||
* | ||
* Must obey the laws defined in cats.laws.CommutativeFlatMapLaws. | ||
*/ | ||
@typeclass trait CommutativeFlatMap[F[_]] extends FlatMap[F] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package cats | ||
|
||
import simulacrum.typeclass | ||
|
||
/** | ||
* Commutative Monad. | ||
* | ||
* Further than a Monad, which just allows composition of dependent effectful functions, | ||
* in a Commutative Monad those functions can be composed in any order, which guarantees | ||
* that their effects do not interfere. | ||
* | ||
* Must obey the laws defined in cats.laws.CommutativeMonadLaws. | ||
*/ | ||
@typeclass trait CommutativeMonad[F[_]] extends Monad[F] with CommutativeFlatMap[F] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package cats | ||
package arrow | ||
|
||
import simulacrum.typeclass | ||
|
||
/** | ||
* In a Commutative Arrow F[_, _], the split operation (or `***`) is commutative, | ||
* which means that there is non-interference between the effect of the paired arrows. | ||
* | ||
* Must obey the laws in CommutativeArrowLaws | ||
*/ | ||
@typeclass trait CommutativeArrow[F[_, _]] extends Arrow[F] | ||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
package cats | ||
package data | ||
|
||
import cats.arrow.{Arrow, Category, Compose, Split} | ||
import cats.arrow.{Arrow, Category, CommutativeArrow, Compose} | ||
import cats.functor.{Contravariant, Profunctor} | ||
import cats.{CoflatMap, Comonad, Functor, Monad} | ||
import cats.{CoflatMap, Comonad, CommutativeComonad, Functor, Monad} | ||
import scala.annotation.tailrec | ||
|
||
/** | ||
|
@@ -45,37 +45,27 @@ object Cokleisli extends CokleisliInstances { | |
} | ||
|
||
private[data] sealed abstract class CokleisliInstances extends CokleisliInstances0 { | ||
implicit def catsDataArrowForCokleisli[F[_]](implicit ev: Comonad[F]): Arrow[Cokleisli[F, ?, ?]] = | ||
new CokleisliArrow[F] { def F: Comonad[F] = ev } | ||
|
||
implicit def catsDataMonadForCokleisli[F[_], A]: Monad[Cokleisli[F, A, ?]] = new Monad[Cokleisli[F, A, ?]] { | ||
def pure[B](x: B): Cokleisli[F, A, B] = | ||
Cokleisli.pure(x) | ||
implicit def catsDataCommutativeArrowForCokleisli[F[_]](implicit ev: CommutativeComonad[F]): CommutativeArrow[Cokleisli[F, ?, ?]] = | ||
new CokleisliCommutativeArrow[F] { def F: CommutativeComonad[F] = ev } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like that the build wasn't happy because you forgot to give this extra help scalac needed. implicit val catsDataCommutativeArrowForCokleisliId: CommutativeArrow[Cokleisli[Id, ?, ?]] =
catsDataCommutativeArrowForCokleisli[Id] |
||
|
||
def flatMap[B, C](fa: Cokleisli[F, A, B])(f: B => Cokleisli[F, A, C]): Cokleisli[F, A, C] = | ||
fa.flatMap(f) | ||
implicit val catsDataCommutativeArrowForCokleisliId: CommutativeArrow[Cokleisli[Id, ?, ?]] = | ||
catsDataCommutativeArrowForCokleisli[Id] | ||
|
||
override def map[B, C](fa: Cokleisli[F, A, B])(f: B => C): Cokleisli[F, A, C] = | ||
fa.map(f) | ||
|
||
def tailRecM[B, C](b: B)(fn: B => Cokleisli[F, A, Either[B, C]]): Cokleisli[F, A, C] = | ||
Cokleisli({ (fa: F[A]) => | ||
@tailrec | ||
def loop(c: Cokleisli[F, A, Either[B, C]]): C = c.run(fa) match { | ||
case Right(c) => c | ||
case Left(bb) => loop(fn(bb)) | ||
} | ||
loop(fn(b)) | ||
}) | ||
} | ||
implicit def catsDataMonadForCokleisli[F[_], A]: Monad[Cokleisli[F, A, ?]] = | ||
new CokleisliMonad[F, A] | ||
|
||
implicit def catsDataMonoidKForCokleisli[F[_]](implicit ev: Comonad[F]): MonoidK[λ[α => Cokleisli[F, α, α]]] = | ||
Category[Cokleisli[F, ?, ?]].algebraK | ||
} | ||
|
||
private[data] sealed abstract class CokleisliInstances0 { | ||
implicit def catsDataSplitForCokleisli[F[_]](implicit ev: CoflatMap[F]): Split[Cokleisli[F, ?, ?]] = | ||
new CokleisliSplit[F] { def F: CoflatMap[F] = ev } | ||
private[data] sealed abstract class CokleisliInstances0 extends CokleisliInstances1 { | ||
implicit def catsDataArrowForCokleisli[F[_]](implicit ev: Comonad[F]): Arrow[Cokleisli[F, ?, ?]] = | ||
new CokleisliArrow[F] { def F: Comonad[F] = ev } | ||
} | ||
|
||
private[data] sealed abstract class CokleisliInstances1 { | ||
implicit def catsDataComposeForCokleisli[F[_]](implicit ev: CoflatMap[F]): Compose[Cokleisli[F, ?, ?]] = | ||
new CokleisliCompose[F] { def F: CoflatMap[F] = ev } | ||
|
||
implicit def catsDataProfunctorForCokleisli[F[_]](implicit ev: Functor[F]): Profunctor[Cokleisli[F, ?, ?]] = | ||
new CokleisliProfunctor[F] { def F: Functor[F] = ev } | ||
|
@@ -89,7 +79,34 @@ private[data] sealed abstract class CokleisliInstances0 { | |
} | ||
} | ||
|
||
private trait CokleisliArrow[F[_]] extends Arrow[Cokleisli[F, ?, ?]] with CokleisliSplit[F] with CokleisliProfunctor[F] { | ||
private[data] trait CokleisliCommutativeArrow[F[_]] extends CommutativeArrow[Cokleisli[F, ?, ?]] with CokleisliArrow[F] { | ||
implicit def F: CommutativeComonad[F] | ||
} | ||
|
||
private[data] class CokleisliMonad[F[_], A] extends Monad[Cokleisli[F, A, ?]] { | ||
|
||
def pure[B](x: B): Cokleisli[F, A, B] = | ||
Cokleisli.pure(x) | ||
|
||
def flatMap[B, C](fa: Cokleisli[F, A, B])(f: B => Cokleisli[F, A, C]): Cokleisli[F, A, C] = | ||
fa.flatMap(f) | ||
|
||
override def map[B, C](fa: Cokleisli[F, A, B])(f: B => C): Cokleisli[F, A, C] = | ||
fa.map(f) | ||
|
||
def tailRecM[B, C](b: B)(fn: B => Cokleisli[F, A, Either[B, C]]): Cokleisli[F, A, C] = | ||
Cokleisli({ (fa: F[A]) => | ||
@tailrec | ||
def loop(c: Cokleisli[F, A, Either[B, C]]): C = c.run(fa) match { | ||
case Right(c) => c | ||
case Left(bb) => loop(fn(bb)) | ||
} | ||
loop(fn(b)) | ||
}) | ||
|
||
} | ||
|
||
private trait CokleisliArrow[F[_]] extends Arrow[Cokleisli[F, ?, ?]] with CokleisliCompose[F] with CokleisliProfunctor[F] { | ||
implicit def F: Comonad[F] | ||
|
||
def lift[A, B](f: A => B): Cokleisli[F, A, B] = | ||
|
@@ -108,17 +125,14 @@ private trait CokleisliArrow[F[_]] extends Arrow[Cokleisli[F, ?, ?]] with Coklei | |
super[CokleisliProfunctor].dimap(fab)(f)(g) | ||
|
||
override def split[A, B, C, D](f: Cokleisli[F, A, B], g: Cokleisli[F, C, D]): Cokleisli[F, (A, C), (B, D)] = | ||
super[CokleisliSplit].split(f, g) | ||
Cokleisli(fac => f.run(F.map(fac)(_._1)) -> g.run(F.map(fac)(_._2))) | ||
} | ||
|
||
private trait CokleisliSplit[F[_]] extends Split[Cokleisli[F, ?, ?]] { | ||
private trait CokleisliCompose[F[_]] extends Compose[Cokleisli[F, ?, ?]] { | ||
implicit def F: CoflatMap[F] | ||
|
||
def compose[A, B, C](f: Cokleisli[F, B, C], g: Cokleisli[F, A, B]): Cokleisli[F, A, C] = | ||
f.compose(g) | ||
|
||
def split[A, B, C, D](f: Cokleisli[F, A, B], g: Cokleisli[F, C, D]): Cokleisli[F, (A, C), (B, D)] = | ||
Cokleisli(fac => f.run(F.map(fac)(_._1)) -> g.run(F.map(fac)(_._2))) | ||
} | ||
|
||
private trait CokleisliProfunctor[F[_]] extends Profunctor[Cokleisli[F, ?, ?]] { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
package cats | ||
package data | ||
|
||
import cats.arrow.{Arrow, Category, Choice, Compose, Split, FunctionK} | ||
import cats.arrow.{Arrow, Category, Choice, CommutativeArrow, Compose, FunctionK} | ||
import cats.functor.{Contravariant, Strong} | ||
|
||
/** | ||
|
@@ -91,11 +91,11 @@ private[data] sealed abstract class KleisliInstances extends KleisliInstances0 { | |
implicit val catsDataMonoidKForKleisliId: MonoidK[λ[α => Kleisli[Id, α, α]]] = | ||
catsDataMonoidKForKleisli[Id] | ||
|
||
implicit def catsDataArrowForKleisli[F[_]](implicit M: Monad[F]): Arrow[Kleisli[F, ?, ?]] = | ||
new KleisliArrow[F] { def F: Monad[F] = M } | ||
implicit def catsDataCommutativeArrowForKleisli[F[_]](implicit M: CommutativeMonad[F]): CommutativeArrow[Kleisli[F, ?, ?]] = | ||
new KleisliCommutativeArrow[F] {def F: CommutativeMonad[F] = M } | ||
|
||
implicit val catsDataArrowForKleisliId: Arrow[Kleisli[Id, ?, ?]] = | ||
catsDataArrowForKleisli[Id] | ||
implicit val catsDataCommutativeArrowForKleisliId: CommutativeArrow[Kleisli[Id, ?, ?]] = | ||
catsDataCommutativeArrowForKleisli[Id] | ||
|
||
implicit def catsDataMonadReaderForKleisliId[A]: MonadReader[Kleisli[Id, A, ?], A] = | ||
catsDataMonadReaderForKleisli[Id, A] | ||
|
@@ -116,6 +116,9 @@ private[data] sealed abstract class KleisliInstances extends KleisliInstances0 { | |
} | ||
|
||
private[data] sealed abstract class KleisliInstances0 extends KleisliInstances1 { | ||
implicit def catsDataArrowForKleisli[F[_]](implicit M: Monad[F]): Arrow[Kleisli[F, ?, ?]] = | ||
new KleisliArrow[F] { def F: Monad[F] = M } | ||
|
||
implicit def catsDataMonadErrorForKleisli[F[_], A, E](implicit ME: MonadError[F, E]): MonadError[Kleisli[F, A, ?], E] = | ||
new KleisliMonadError[F, A, E] { def F: MonadError[F, E] = ME } | ||
} | ||
|
@@ -132,8 +135,8 @@ private[data] sealed abstract class KleisliInstances2 extends KleisliInstances3 | |
implicit val catsDataChoiceForKleisliId: Choice[Kleisli[Id, ?, ?]] = | ||
catsDataChoiceForKleisli[Id] | ||
|
||
implicit def catsDataSplitForKleisli[F[_]](implicit FM: FlatMap[F]): Split[Kleisli[F, ?, ?]] = | ||
new KleisliSplit[F] { def F: FlatMap[F] = FM } | ||
implicit def catsDataComposeForKleisli[F[_]](implicit FM: FlatMap[F]): Compose[Kleisli[F, ?, ?]] = | ||
new KleisliCompose[F] { def F: FlatMap[F] = FM } | ||
|
||
implicit def catsDataStrongForKleisli[F[_]](implicit F0: Functor[F]): Strong[Kleisli[F, ?, ?]] = | ||
new KleisliStrong[F] { def F: Functor[F] = F0 } | ||
|
@@ -163,15 +166,15 @@ private[data] sealed abstract class KleisliInstances5 { | |
new KleisliFunctor[F, A] { def F: Functor[F] = F0 } | ||
} | ||
|
||
private trait KleisliArrow[F[_]] extends Arrow[Kleisli[F, ?, ?]] with KleisliSplit[F] with KleisliStrong[F] with KleisliCategory[F] { | ||
private trait KleisliCommutativeArrow[F[_]] extends CommutativeArrow[Kleisli[F, ?, ?]] with KleisliArrow[F] { | ||
implicit def F: CommutativeMonad[F] | ||
} | ||
|
||
private trait KleisliArrow[F[_]] extends Arrow[Kleisli[F, ?, ?]] with KleisliCategory[F] with KleisliStrong[F] { | ||
implicit def F: Monad[F] | ||
|
||
def lift[A, B](f: A => B): Kleisli[F, A, B] = | ||
Kleisli(a => F.pure(f(a))) | ||
} | ||
|
||
private trait KleisliSplit[F[_]] extends Split[Kleisli[F, ?, ?]] with KleisliCompose[F] { | ||
implicit def F: FlatMap[F] | ||
|
||
override def split[A, B, C, D](f: Kleisli[F, A, B], g: Kleisli[F, C, D]): Kleisli[F, (A, C), (B, D)] = | ||
Kleisli{ case (a, c) => F.flatMap(f.run(a))(b => F.map(g.run(c))(d => (b, d))) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same situation here as in |
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package cats | ||
package syntax | ||
|
||
import cats.arrow.Arrow | ||
|
||
trait ArrowSyntax extends Arrow.ToArrowOps |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
quick note, codecov somehow mistakenly thinks this line is uncovered.