-
-
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
Replace Split with Commutative Arrow. Continuing #1719 #1766
Changes from 14 commits
50087b5
a8806ee
495ad23
21fc3fa
ea5a064
64965c2
8fe26df
9603c82
bc0f309
c5ab4a5
b77427b
914c564
3e975bd
41edd56
f34c6e5
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 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 |
---|---|---|
|
@@ -5,10 +5,16 @@ import cats.functor.Strong | |
|
||
import simulacrum.typeclass | ||
|
||
@typeclass trait Arrow[F[_, _]] extends Split[F] with Strong[F] with Category[F] { self => | ||
/** | ||
* Must obey the laws defined in cats.laws.ArrowLaws. | ||
*/ | ||
@typeclass trait Arrow[F[_, _]] extends Category[F] with Strong[F] { self => | ||
|
||
/** | ||
* Lift a function into the context of an Arrow | ||
* Lift a function into the context of an Arrow. | ||
* | ||
* In the reference articles "Arrows are Promiscuous...", and in the corresponding Haskell | ||
* library `Control.Arrow`, this function is called `arr`. | ||
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. 👍 |
||
*/ | ||
def lift[A, B](f: A => B): F[A, B] | ||
|
||
|
@@ -20,6 +26,25 @@ import simulacrum.typeclass | |
compose(swap, compose(first[A, B, C](fa), swap)) | ||
} | ||
|
||
override def split[A, B, C, D](f: F[A, B], g: F[C, D]): F[(A, C), (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. 👍 |
||
* Create a new computation `F` that splits its input between `f` and `g` | ||
* and combines the output of each. | ||
* | ||
* Example: | ||
* {{{ | ||
* scala> import cats.implicits._ | ||
* scala> import cats.arrow.Arrow | ||
* scala> val toLong: Int => Long = _.toLong | ||
* scala> val toDouble: Float => Double = _.toDouble | ||
* scala> val f: ((Int, Float)) => (Long, Double) = Arrow[Function1].split(toLong, toDouble) | ||
* scala> f((3, 4.0f)) | ||
* res0: (Long, Double) = (3,4.0) | ||
* }}} | ||
* | ||
* Note that the arrow laws do not guarantee the non-interference between the _effects_ of | ||
* `f` and `g` in the context of F. This means that `f *** g` may not be equivalent to `g *** f`. | ||
*/ | ||
@simulacrum.op("***", alias = true) | ||
def split[A, B, C, D](f: F[A, B], g: F[C, D]): F[(A, C), (B, D)] = | ||
andThen(first(f), second(g)) | ||
} |
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,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} | ||
|
||
/** | ||
|
@@ -81,7 +81,13 @@ private[data] sealed trait KleisliFunctions { | |
} | ||
|
||
private[data] sealed abstract class KleisliInstances extends KleisliInstances0 { | ||
implicit def catsDataCommutativeMonadForKleisli[F[_], A, B](implicit F0: CommutativeMonad[F]): CommutativeMonad[Kleisli[F, A, ?]] = | ||
new KleisliMonad[F, A] with CommutativeMonad[Kleisli[F, A, ?]] { | ||
implicit def F: Monad[F] = F0 | ||
} | ||
} | ||
|
||
private[data] sealed abstract class KleisliInstances0 extends KleisliInstances1 { | ||
implicit def catsDataMonoidForKleisli[F[_], A, B](implicit FB0: Monoid[F[B]]): Monoid[Kleisli[F, A, B]] = | ||
new KleisliMonoid[F, A, B] { def FB: Monoid[F[B]] = FB0 } | ||
|
||
|
@@ -91,11 +97,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] = | ||
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.
|
||
catsDataMonadReaderForKleisli[Id, A] | ||
|
@@ -115,25 +121,28 @@ private[data] sealed abstract class KleisliInstances extends KleisliInstances0 { | |
new KleisliApplicativeError[F, A, E] { def F: ApplicativeError[F, E] = AE } | ||
} | ||
|
||
private[data] sealed abstract class KleisliInstances0 extends KleisliInstances1 { | ||
private[data] sealed abstract class KleisliInstances1 extends KleisliInstances2 { | ||
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 } | ||
} | ||
|
||
private[data] sealed abstract class KleisliInstances1 extends KleisliInstances2 { | ||
private[data] sealed abstract class KleisliInstances2 extends KleisliInstances3 { | ||
implicit def catsDataMonadReaderForKleisli[F[_], A](implicit M: Monad[F]): MonadReader[Kleisli[F, A, ?], A] = | ||
new KleisliMonadReader[F, A] { def F: Monad[F] = M } | ||
} | ||
|
||
private[data] sealed abstract class KleisliInstances2 extends KleisliInstances3 { | ||
private[data] sealed abstract class KleisliInstances3 extends KleisliInstances4 { | ||
implicit def catsDataChoiceForKleisli[F[_]](implicit M: Monad[F]): Choice[Kleisli[F, ?, ?]] = | ||
new KleisliChoice[F] { def F: Monad[F] = M } | ||
|
||
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 } | ||
|
@@ -148,30 +157,30 @@ private[data] sealed abstract class KleisliInstances2 extends KleisliInstances3 | |
Compose[Kleisli[F, ?, ?]].algebraK | ||
} | ||
|
||
private[data] sealed abstract class KleisliInstances3 extends KleisliInstances4 { | ||
private[data] sealed abstract class KleisliInstances4 extends KleisliInstances5 { | ||
implicit def catsDataApplicativeForKleisli[F[_], A](implicit A: Applicative[F]): Applicative[Kleisli[F, A, ?]] = | ||
new KleisliApplicative[F, A] { def F: Applicative[F] = A } | ||
} | ||
|
||
private[data] sealed abstract class KleisliInstances4 extends KleisliInstances5 { | ||
private[data] sealed abstract class KleisliInstances5 extends KleisliInstances6 { | ||
implicit def catsDataApplyForKleisli[F[_], A](implicit A: Apply[F]): Apply[Kleisli[F, A, ?]] = | ||
new KleisliApply[F, A] { def F: Apply[F] = A } | ||
} | ||
|
||
private[data] sealed abstract class KleisliInstances5 { | ||
private[data] sealed abstract class KleisliInstances6 { | ||
implicit def catsDataFunctorForKleisli[F[_], A](implicit F0: Functor[F]): Functor[Kleisli[F, A, ?]] = | ||
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 comment
The reason will be displayed to describe this comment to others. Learn more.
👍