From c0051110633290af7c93109bf0cf12a042998f90 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Fri, 28 Dec 2018 12:46:46 -0800 Subject: [PATCH] Moving binary incompatible change out into FoldableSyntaxBinCompat0 --- core/src/main/scala/cats/Foldable.scala | 32 ---------------- core/src/main/scala/cats/implicits.scala | 1 + core/src/main/scala/cats/syntax/all.scala | 3 ++ .../src/main/scala/cats/syntax/foldable.scala | 38 +++++++++++++++++++ 4 files changed, 42 insertions(+), 32 deletions(-) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index 211b5597779..f4256113027 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -506,38 +506,6 @@ import Foldable.sentinel ) } - /** - * Separate this Foldable into a Tuple by an effectful separating function `A => G[Either[B, C]]` - * Equivalent to `Bitraversable#traverse` over `Alternative#separate` - * - * {{{ - * scala> import cats.implicits._ - * scala> val list = List(1,2,3,4) - * scala> val partitioned1 = Foldable[List].partitionEitherM(list)(a => if (a % 2 == 0) Eval.now(Either.left[String, Int](a.toString)) else Eval.now(Either.right[String, Int](a))) - * Since `Eval.now` yields a lazy computation, we need to force it to inspect the result: - * scala> partitioned1.value - * res0: (List[String], List[Int]) = (List(2, 4),List(1, 3)) - * scala> val partitioned2 = Foldable[List].partitionEitherM(list)(a => Eval.later(Either.right(a * 4))) - * scala> partitioned2.value - * res1: (List[Nothing], List[Int]) = (List(),List(4, 8, 12, 16)) - * }}} - */ - def partitionEitherM[G[_], A, B, C](fa: F[A])(f: A => G[Either[B, C]])(implicit A: Alternative[F], - M: Monad[G]): G[(F[B], F[C])] = { - import cats.instances.tuple._ - - implicit val mb: Monoid[F[B]] = A.algebra[B] - implicit val mc: Monoid[F[C]] = A.algebra[C] - - foldMapM[G, A, (F[B], F[C])](fa)( - a => - M.map(f(a)) { - case Right(c) => (A.empty[B], A.pure(c)) - case Left(b) => (A.pure(b), A.empty[C]) - } - ) - } - /** * Convert F[A] to a List[A], only including elements which match `p`. */ diff --git a/core/src/main/scala/cats/implicits.scala b/core/src/main/scala/cats/implicits.scala index f04f033c732..1267851ae60 100644 --- a/core/src/main/scala/cats/implicits.scala +++ b/core/src/main/scala/cats/implicits.scala @@ -6,6 +6,7 @@ object implicits with syntax.AllSyntaxBinCompat1 with syntax.AllSyntaxBinCompat2 with syntax.AllSyntaxBinCompat3 + with syntax.AllSyntaxBinCompat4 with instances.AllInstances with instances.AllInstancesBinCompat0 with instances.AllInstancesBinCompat1 diff --git a/core/src/main/scala/cats/syntax/all.scala b/core/src/main/scala/cats/syntax/all.scala index ec7fbec6308..106efac663b 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -7,6 +7,7 @@ abstract class AllSyntaxBinCompat with AllSyntaxBinCompat1 with AllSyntaxBinCompat2 with AllSyntaxBinCompat3 + with AllSyntaxBinCompat4 trait AllSyntax extends AlternativeSyntax @@ -77,3 +78,5 @@ trait AllSyntaxBinCompat2 with ValidatedSyntaxBincompat0 trait AllSyntaxBinCompat3 extends UnorderedFoldableSyntax with Function1Syntax + +trait AllSyntaxBinCompat4 extends FoldableSyntaxBinCompat0 diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 2df84238472..5e5f713b916 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -190,5 +190,43 @@ final class FoldableOps[F[_], A](private val fa: F[A]) extends AnyVal { case None ⇒ acc } ) +} + +trait FoldableSyntaxBinCompat0 { + implicit final def catsSyntaxFoldableBinCompat0[F[_]](fa: Foldable[F]): FoldableOpsBinCompat0[F] = + new FoldableOpsBinCompat0(fa) +} + +final class FoldableOpsBinCompat0[F[_]](private val F: Foldable[F]) extends AnyVal { + /** + * Separate this Foldable into a Tuple by an effectful separating function `A => G[Either[B, C]]` + * Equivalent to `Bitraversable#traverse` over `Alternative#separate` + * + * {{{ + * scala> import cats.implicits._, cats.Foldable, cats.Eval + * scala> val list = List(1,2,3,4) + * scala> val partitioned1 = Foldable[List].partitionEitherM(list)(a => if (a % 2 == 0) Eval.now(Either.left[String, Int](a.toString)) else Eval.now(Either.right[String, Int](a))) + * Since `Eval.now` yields a lazy computation, we need to force it to inspect the result: + * scala> partitioned1.value + * res0: (List[String], List[Int]) = (List(2, 4),List(1, 3)) + * scala> val partitioned2 = Foldable[List].partitionEitherM(list)(a => Eval.later(Either.right(a * 4))) + * scala> partitioned2.value + * res1: (List[Nothing], List[Int]) = (List(),List(4, 8, 12, 16)) + * }}} + */ + def partitionEitherM[G[_], A, B, C](fa: F[A])(f: A => G[Either[B, C]])(implicit A: Alternative[F], + M: Monad[G]): G[(F[B], F[C])] = { + import cats.instances.tuple._ + + implicit val mb: Monoid[F[B]] = A.algebra[B] + implicit val mc: Monoid[F[C]] = A.algebra[C] + F.foldMapM[G, A, (F[B], F[C])](fa)( + a => + M.map(f(a)) { + case Right(c) => (A.empty[B], A.pure(c)) + case Left(b) => (A.pure(b), A.empty[C]) + } + ) + } }