Skip to content

Commit

Permalink
change FM type from Monad to FlatMap
Browse files Browse the repository at this point in the history
  • Loading branch information
satorg committed Nov 8, 2021
1 parent a01284e commit 25da570
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 21 deletions.
34 changes: 25 additions & 9 deletions core/src/main/scala/cats/Alternative.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ import scala.annotation.implicitNotFound
@implicitNotFound("Could not find an instance of Alternative for ${F}")
@typeclass trait Alternative[F[_]] extends Applicative[F] with MonoidK[F] { self =>

// Note: `protected` is only necessary to enforce binary compatibility
// since neither `private` nor `private[cats]` work properly here.
@deprecated("use a FlatMap-constrained version instead", "2.6.2")
protected def unite[G[_], A](fga: F[G[A]])(FM: Monad[F], G: Foldable[G]): F[A] = {
implicit def FM0: FlatMap[F] = FM
implicit def G0: Foldable[G] = G
unite(fga)
}

/**
* Fold over the inner structure to combine all of the values with
* our combine method inherited from MonoidK. The result is for us
Expand All @@ -15,29 +24,34 @@ import scala.annotation.implicitNotFound
*
* Example:
* {{{
* scala> import cats.implicits._
* scala> val x: List[Vector[Int]] = List(Vector(1, 2), Vector(3, 4))
* scala> Alternative[List].unite(x)
* res0: List[Int] = List(1, 2, 3, 4)
* }}}
*/
def unite[G[_], A](fga: F[G[A]])(implicit FM: Monad[F], G: Foldable[G]): F[A] =
FM.flatMap(fga) { ga =>
G.foldLeft(ga, empty[A])((acc, a) => combineK(acc, pure(a)))
}
def unite[G[_], A](fga: F[G[A]])(implicit FM: FlatMap[F], G: Foldable[G]): F[A] =
FM.flatMap(fga) { G.foldMapK(_)(pure)(self) }

// Note: `protected` is only necessary to enforce binary compatibility
// since neither `private` nor `private[cats]` work properly here.
@deprecated("use a FlatMap-constrained version instead", "2.6.2")
protected def separate[G[_, _], A, B](fgab: F[G[A, B]])(FM: Monad[F], G: Bifoldable[G]): (F[A], F[B]) = {
implicit def FM0: FlatMap[F] = FM
implicit def G0: Bifoldable[G] = G
separate(fgab)
}

/**
* Separate the inner foldable values into the "lefts" and "rights"
*
* Example:
* {{{
* scala> import cats.implicits._
* scala> val l: List[Either[String, Int]] = List(Right(1), Left("error"))
* scala> Alternative[List].separate(l)
* res0: (List[String], List[Int]) = (List(error),List(1))
* }}}
*/
def separate[G[_, _], A, B](fgab: F[G[A, B]])(implicit FM: Monad[F], G: Bifoldable[G]): (F[A], F[B]) = {
def separate[G[_, _], A, B](fgab: F[G[A, B]])(implicit FM: FlatMap[F], G: Bifoldable[G]): (F[A], F[B]) = {
val as = FM.flatMap(fgab)(gab => G.bifoldMap(gab)(pure, _ => empty[A])(algebra[A]))
val bs = FM.flatMap(fgab)(gab => G.bifoldMap(gab)(_ => empty[B], pure)(algebra[B]))
(as, bs)
Expand Down Expand Up @@ -116,9 +130,11 @@ object Alternative {
def self: F[A]
val typeClassInstance: TypeClassType
def unite[G[_], B](implicit ev$1: A <:< G[B], FM: Monad[F], G: Foldable[G]): F[B] =
typeClassInstance.unite[G, B](self.asInstanceOf[F[G[B]]])(FM, G)
// Note: edited manually since seems Simulacrum is not able to handle the bin-compat redirection properly.
typeClassInstance.unite[G, B](self.asInstanceOf[F[G[B]]])
def separate[G[_, _], B, C](implicit ev$1: A <:< G[B, C], FM: Monad[F], G: Bifoldable[G]): (F[B], F[C]) =
typeClassInstance.separate[G, B, C](self.asInstanceOf[F[G[B, C]]])(FM, G)
// Note: edited manually since seems Simulacrum is not able to handle the bin-compat redirection properly.
typeClassInstance.separate[G, B, C](self.asInstanceOf[F[G[B, C]]])
def separateFoldable[G[_, _], B, C](implicit ev$1: A <:< G[B, C], G: Bifoldable[G], FF: Foldable[F]): (F[B], F[C]) =
typeClassInstance.separateFoldable[G, B, C](self.asInstanceOf[F[G[B, C]]])(G, FF)
}
Expand Down
50 changes: 39 additions & 11 deletions core/src/main/scala/cats/syntax/alternative.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,23 @@ trait AlternativeSyntax {
new GuardOps(b)
}

final class UniteOps[F[_], G[_], A](private val fga: F[G[A]]) extends AnyVal {
final class UniteOps[F[_], G[_], A] private[syntax] (protected val fga: F[G[A]])
extends AnyVal
with UniteOpsBinCompat1[F, G, A] {

@deprecated("use a FlatMap-constrained instead", "2.6.2")
protected def unite(F: Monad[F], A: Alternative[F], G: Foldable[G]): F[A] =
A.unite(fga)(F, G)
}

sealed private[syntax] trait UniteOpsBinCompat1[F[_], G[_], A] extends Any { self: UniteOps[F, G, A] =>

/**
* @see [[Alternative.unite]]
* Fold over the inner structure to combine all of the values with
* our combine method inherited from MonoidK. The result is for us
* to accumulate all of the "interesting" values of the inner G, so
* if G is Option, we collect all the Some values, if G is Either,
* we collect all the Right values, etc.
*
* Example:
* {{{
Expand All @@ -26,37 +39,52 @@ final class UniteOps[F[_], G[_], A](private val fga: F[G[A]]) extends AnyVal {
* res0: List[Int] = List(1, 2, 3, 4)
* }}}
*/
def unite(implicit F: Monad[F], A: Alternative[F], G: Foldable[G]): F[A] = A.unite[G, A](fga)
def unite(implicit F: FlatMap[F], A: Alternative[F], G: Foldable[G]): F[A] =
A.unite[G, A](fga)
}

final class SeparateOps[F[_], G[_, _], A, B](private val fgab: F[G[A, B]]) extends AnyVal {
final class SeparateOps[F[_], G[_, _], A, B] private[syntax] (protected val fgab: F[G[A, B]])
extends AnyVal
with SeparateOpsBinCompat[F, G, A, B] {

@deprecated("use a FlatMap-constrained version instead", "2.6.2")
protected def separate(F: Monad[F], A: Alternative[F], G: Bifoldable[G]): (F[A], F[B]) =
A.separate[G, A, B](fgab)(F, G)

/**
* @see [[Alternative.separate]]
* Separate the inner foldable values into the "lefts" and "rights".
* A variant of [[separate]] that is specialized
* for Fs that have Foldable instances
* which allows for a single-pass implementation
* (as opposed to {{{separate}}} which is 2-pass).
*
* Example:
* {{{
* scala> import cats.implicits._
* scala> val l: List[Either[String, Int]] = List(Right(1), Left("error"))
* scala> l.separate
* scala> l.separateFoldable
* res0: (List[String], List[Int]) = (List(error),List(1))
* }}}
*/
def separate(implicit F: Monad[F], A: Alternative[F], G: Bifoldable[G]): (F[A], F[B]) = A.separate[G, A, B](fgab)
def separateFoldable(implicit F: Foldable[F], A: Alternative[F], G: Bifoldable[G]): (F[A], F[B]) =
A.separateFoldable[G, A, B](fgab)
}

sealed private[syntax] trait SeparateOpsBinCompat[F[_], G[_, _], A, B] extends Any { self: SeparateOps[F, G, A, B] =>

/**
* @see [[Alternative.separateFoldable]]
* Separate the inner foldable values into the "lefts" and "rights"
*
* Example:
* {{{
* scala> import cats.implicits._
* scala> val l: List[Either[String, Int]] = List(Right(1), Left("error"))
* scala> l.separateFoldable
* scala> l.separate
* res0: (List[String], List[Int]) = (List(error),List(1))
* }}}
*/
def separateFoldable(implicit F: Foldable[F], A: Alternative[F], G: Bifoldable[G]): (F[A], F[B]) =
A.separateFoldable[G, A, B](fgab)
def separate(implicit F: FlatMap[F], A: Alternative[F], G: Bifoldable[G]): (F[A], F[B]) =
A.separate[G, A, B](fgab)
}

final class GuardOps(private val condition: Boolean) extends AnyVal {
Expand Down
2 changes: 1 addition & 1 deletion tests/src/test/scala/cats/tests/SyntaxSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ object SyntaxSuite {
val gfab2 = fgab.leftSequence
}

def testAlternativeMonad[F[_]: Alternative: Monad, G[_]: Foldable, H[_, _]: Bifoldable, A, B]: Unit = {
def testAlternativeMonad[F[_]: Alternative: FlatMap, G[_]: Foldable, H[_, _]: Bifoldable, A, B]: Unit = {
val fga = mock[F[G[A]]]
val fa = fga.unite

Expand Down

0 comments on commit 25da570

Please sign in to comment.