From 305b40ebef96a94808e98489aeab0a04527c75c4 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Sat, 24 Nov 2018 13:29:22 -0800 Subject: [PATCH 01/17] Adding partitionEither --- core/src/main/scala/cats/Foldable.scala | 29 ++++++++++ .../test/scala/cats/tests/FoldableSuite.scala | 57 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index f425611302..7ae1a51aeb 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -506,6 +506,35 @@ 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> Foldable[List].partitionEitherM(list)(a => if (a % 2 == 0) Eval.now(Left(a.toString)) else Eval.now(Right(a))).value + * res0: (List[String], List[Int]) = (List(2, 4),List(1, 3)) + * scala> Foldable[List].partitionEitherM(list)(a => Eval.later(Either.right(a * 4))).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/tests/src/test/scala/cats/tests/FoldableSuite.scala b/tests/src/test/scala/cats/tests/FoldableSuite.scala index 2521f30394..2b9e28e093 100644 --- a/tests/src/test/scala/cats/tests/FoldableSuite.scala +++ b/tests/src/test/scala/cats/tests/FoldableSuite.scala @@ -78,6 +78,63 @@ abstract class FoldableSuite[F[_]: Foldable](name: String)(implicit ArbFInt: Arb } } + test("Foldable#partitionEitherM retains size") { + import cats.syntax.foldable._ + forAll { (fi: F[Int], f: Int => Either[String, String]) => + val vector = Foldable[F].toList(fi).toVector + val result = Foldable[Vector].partitionEitherM(vector)(f.andThen(Option.apply)).map { + case (lefts, rights) => + (lefts <+> rights).size + } + result should ===(Option(vector.size)) + } + } + + test("Foldable#partitionEitherM consistent with List#partition") { + import cats.syntax.foldable._ + forAll { (fi: F[Int], f: Int => Either[String, String]) => + val list = Foldable[F].toList(fi) + val partitioned = Foldable[List].partitionEitherM(list)(f.andThen(Option.apply)) + val (ls, rs) = list + .map(f) + .partition({ + case Left(_) => true + case Right(_) => false + }) + + partitioned.map(_._1.map(_.asLeft[String])) should ===(Option(ls)) + partitioned.map(_._2.map(_.asRight[String])) should ===(Option(rs)) + } + } + + test("Foldable#partitionEitherM to one side is identity") { + import cats.syntax.foldable._ + forAll { (fi: F[Int], f: Int => String) => + val list = Foldable[F].toList(fi) + val g: Int => Option[Either[Double, String]] = f.andThen(Right.apply).andThen(Option.apply) + val h: Int => Option[Either[String, Double]] = f.andThen(Left.apply).andThen(Option.apply) + + val withG = Foldable[List].partitionEitherM(list)(g).map(_._2) + withG should ===(Option(list.map(f))) + + val withH = Foldable[List].partitionEitherM(list)(h).map(_._1) + withH should ===(Option(list.map(f))) + } + } + + test("Foldable#partitionEitherM remains sorted") { + import cats.syntax.foldable._ + forAll { (fi: F[Int], f: Int => Either[String, String]) => + val list = Foldable[F].toList(fi) + + val sorted = list.map(f).sorted + val pairs = Foldable[List].partitionEitherM(sorted)(Option.apply) + + pairs.map(_._1.sorted) should ===(pairs.map(_._1)) + pairs.map(_._2.sorted) should ===(pairs.map(_._2)) + } + } + test(s"Foldable[$name] summation") { forAll { (fa: F[Int]) => val total = iterator(fa).sum From 6c1afdc9b79a70c34f85924396c59bef88c03ad7 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Sun, 25 Nov 2018 19:16:02 -0800 Subject: [PATCH 02/17] Resolving 2.11 Product with Serializable inference --- core/src/main/scala/cats/Foldable.scala | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index 7ae1a51aeb..211b559777 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -513,9 +513,12 @@ import Foldable.sentinel * {{{ * scala> import cats.implicits._ * scala> val list = List(1,2,3,4) - * scala> Foldable[List].partitionEitherM(list)(a => if (a % 2 == 0) Eval.now(Left(a.toString)) else Eval.now(Right(a))).value + * 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> Foldable[List].partitionEitherM(list)(a => Eval.later(Either.right(a * 4))).value + * 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)) * }}} */ From f36ce95e133b3e93e6afe4a27f0e798a43ce41e0 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Fri, 28 Dec 2018 12:46:46 -0800 Subject: [PATCH 03/17] Moving binary incompatible change out into FoldableSyntaxBinCompat1 --- core/src/main/scala/cats/Foldable.scala | 32 -------- core/src/main/scala/cats/implicits.scala | 1 + core/src/main/scala/cats/syntax/all.scala | 2 + .../src/main/scala/cats/syntax/foldable.scala | 74 ++++++++++++++++++- core/src/main/scala/cats/syntax/package.scala | 2 +- 5 files changed, 77 insertions(+), 34 deletions(-) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index 211b559777..f425611302 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 1267851ae6..1f78ae3cb4 100644 --- a/core/src/main/scala/cats/implicits.scala +++ b/core/src/main/scala/cats/implicits.scala @@ -7,6 +7,7 @@ object implicits with syntax.AllSyntaxBinCompat2 with syntax.AllSyntaxBinCompat3 with syntax.AllSyntaxBinCompat4 + with syntax.AllSyntaxBinCompat5 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 5a65ddeaf5..1a65e02222 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -84,3 +84,5 @@ trait AllSyntaxBinCompat4 with ParallelApplySyntax with FoldableSyntaxBinCompat0 with ReducibleSyntaxBinCompat0 + +trait AllSyntaxBinCompat5 extends FoldableSyntaxBinCompat1 diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 93e130d142..9c702d9116 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -14,6 +14,11 @@ trait FoldableSyntaxBinCompat0 { new FoldableOps0[F, A](fa) } +trait FoldableSyntaxBinCompat1 { + implicit final def catsSyntaxFoldableBinCompat0[F[_]](fa: Foldable[F]): FoldableOps1[F] = + new FoldableOps1(fa) +} + final class NestedFoldableOps[F[_], G[_], A](private val fga: F[G[A]]) extends AnyVal { def sequence_(implicit F: Foldable[F], G: Applicative[G]): G[Unit] = F.sequence_(fga) @@ -195,7 +200,6 @@ final class FoldableOps[F[_], A](private val fa: F[A]) extends AnyVal { case None ⇒ acc } ) - } final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { @@ -214,4 +218,72 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { * */ def foldMapK[G[_], B](f: A => G[B])(implicit F: Foldable[F], G: MonoidK[G]): G[B] = F.foldMap(fa)(f)(G.algebra) + + /** + * 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.Eval + * scala> val list = List(1,2,3,4) + * scala> val partitioned1 = list.partitionEitherM(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 = list.partitionEitherM(a => Eval.later(Either.right(a * 4))) + * scala> partitioned2.value + * res1: (List[Nothing], List[Int]) = (List(),List(4, 8, 12, 16)) + * }}} + */ + def partitionEitherM[G[_], B, C]( + f: A => G[Either[B, C]] + )(implicit A: Alternative[F], F: Foldable[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]) + } + ) + } +} + +final class FoldableOps1[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]) + } + ) + } } diff --git a/core/src/main/scala/cats/syntax/package.scala b/core/src/main/scala/cats/syntax/package.scala index a4f02e5596..7bd0ac8514 100644 --- a/core/src/main/scala/cats/syntax/package.scala +++ b/core/src/main/scala/cats/syntax/package.scala @@ -26,7 +26,7 @@ package object syntax { object either extends EitherSyntax with EitherSyntaxBinCompat0 object eq extends EqSyntax object flatMap extends FlatMapSyntax - object foldable extends FoldableSyntax with FoldableSyntaxBinCompat0 + object foldable extends FoldableSyntax with FoldableSyntaxBinCompat0 with FoldableSyntaxBinCompat1 object functor extends FunctorSyntax object functorFilter extends FunctorFilterSyntax object group extends GroupSyntax From a23b71d6697891b0ca47172c395317103f650df2 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Sat, 12 Jan 2019 15:16:03 -0800 Subject: [PATCH 04/17] Fixing merge conflict --- core/src/main/scala/cats/implicits.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/scala/cats/implicits.scala b/core/src/main/scala/cats/implicits.scala index 99ee337181..6094afa1b9 100644 --- a/core/src/main/scala/cats/implicits.scala +++ b/core/src/main/scala/cats/implicits.scala @@ -7,7 +7,6 @@ object implicits with syntax.AllSyntaxBinCompat2 with syntax.AllSyntaxBinCompat3 with syntax.AllSyntaxBinCompat4 - with syntax.AllSyntaxBinCompat5 with instances.AllInstances with instances.AllInstancesBinCompat0 with instances.AllInstancesBinCompat1 From a522b0ff2476b3808fe7ca1fe149b0b06bf15090 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Sat, 12 Jan 2019 15:15:55 -0800 Subject: [PATCH 05/17] Deduplicating partitionEitherM --- core/src/main/scala/cats/syntax/foldable.scala | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 9c702d9116..f13332a2ef 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -238,18 +238,8 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { def partitionEitherM[G[_], B, C]( f: A => G[Either[B, C]] )(implicit A: Alternative[F], F: Foldable[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]) - } - ) + import cats.syntax.foldable._ + F.partitionEitherM[G, A, B, C](fa)(f)(A, M) } } From f394412631e862f329a72cbdd5fda04139578664 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Sun, 13 Jan 2019 18:13:24 -0800 Subject: [PATCH 06/17] Splitting out partitionBifoldableM --- .../src/main/scala/cats/syntax/foldable.scala | 71 +++++++++++++++---- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index f13332a2ef..a4801c7ed5 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -219,6 +219,29 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { def foldMapK[G[_], B](f: A => G[B])(implicit F: Foldable[F], G: MonoidK[G]): G[B] = F.foldMap(fa)(f)(G.algebra) + /** + * Separate this Foldable into a Tuple by an effectful separating function `A => G[H[B, C]]` for some `Bifoldable[H]` + * Equivalent to `Bitraverse#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].partitionBifoldableM(list)(a => (Free.pure((a, s"value ${a}"))): Free[Id, Tuple2[Int, String]]) + * Since `Free.pure` yields a deferred computation, we need to force it to inspect the result: + * scala> partitioned1.run + * res0: (List[Int], List[String]) = (List(1, 2, 3, 4),List(value 1, value 2, value 3, value 4)) + * `Const`'s second parameter is never instantiated, so we can use an impossible type: + * scala> Foldable[List].partitionEitherM(list)(a => Option(Const[Int, Nothing with Any](a))) + * res1: (List[Int], List[Nothing with Any]) = (List(1, 2, 3, 4), List()) + * }}} + */ + def partitionBifoldableM[G[_], H[_, _], B, C]( + fa: F[A] + )(f: A => G[H[B, C]])(implicit A: Alternative[F], F: Foldable[F], M: Monad[G], H: Bifoldable[H]): G[(F[B], F[C])] = { + import cats.syntax.foldable._ + F.partitionBifoldableM[G, H, A, B, C](fa)(f)(A, M, H) + } + /** * Separate this Foldable into a Tuple by an effectful separating function `A => G[Either[B, C]]` * Equivalent to `Bitraversable#traverse` over `Alternative#separate` @@ -246,23 +269,24 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { final class FoldableOps1[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` + * Separate this Foldable into a Tuple by an effectful separating function `A => G[H[B, C]]` for some `Bifoldable[H]` + * Equivalent to `Bitraverse#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)) + * scala> val partitioned1 = Foldable[List].partitionBifoldableM(list)(a => (Free.pure((a, s"value ${a}"))): Free[Id, Tuple2[Int, String]]) + * Since `Free.pure` yields a deferred computation, we need to force it to inspect the result: + * scala> partitioned1.run + * res0: (List[Int], List[String]) = (List(1, 2, 3, 4),List(value 1, value 2, value 3, value 4)) + * `Const`'s second parameter is never instantiated, so we can use an impossible type: + * scala> Foldable[List].partitionEitherM(list)(a => Option(Const[Int, Nothing with Any](a))) + * res1: (List[Int], List[Nothing with Any]) = (List(1, 2, 3, 4), List()) * }}} */ - 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])] = { + def partitionBifoldableM[G[_], H[_, _], A, B, C]( + fa: F[A] + )(f: A => G[H[B, C]])(implicit A: Alternative[F], M: Monad[G], H: Bifoldable[H]): G[(F[B], F[C])] = { import cats.instances.tuple._ implicit val mb: Monoid[F[B]] = A.algebra[B] @@ -271,9 +295,30 @@ final class FoldableOps1[F[_]](private val F: Foldable[F]) extends AnyVal { 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]) + H.bifoldMap[B, C, (F[B], F[C])](_)(b => (A.pure(b), A.empty[C]), c => (A.empty[B], A.pure(c))) } ) } + + /** + * Separate this Foldable into a Tuple by an effectful separating function `A => G[Either[B, C]]` + * Equivalent to `Bitraverse#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.either._ + partitionBifoldableM[G, Either, A, B, C](fa)(f)(A, M, Bifoldable[Either]) + } } From 0912a588485e3004dba5dfe4bb8c5b4f5ae08efd Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Sun, 13 Jan 2019 18:13:46 -0800 Subject: [PATCH 07/17] Generalizing partitionBifoldable --- .../src/main/scala/cats/syntax/foldable.scala | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index a4801c7ed5..359d9b6821 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -219,6 +219,27 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { def foldMapK[G[_], B](f: A => G[B])(implicit F: Foldable[F], G: MonoidK[G]): G[B] = F.foldMap(fa)(f)(G.algebra) + /** + * Separate this Foldable into a Tuple by an effectful separating function `A => H[B, C]` for some `Bifoldable[H]` + * Equivalent to `Functor#map` over `Alternative#separate` + * + * {{{ + * scala> import cats.implicits._, cats.Foldable, cats.Eval + * scala> val list = List(1,2,3,4) + * scala> Foldable[List].partitionBifoldable(list)(a => (a, s"value ${a}")) + * res0: (List[Int], List[String]) = (List(1, 2, 3, 4),List(value 1, value 2, value 3, value 4)) + * `Const`'s second parameter is never instantiated, so we can use an impossible type: + * scala> Foldable[List].partitionBifoldable(list)(a => Option(Const[Int, Nothing with Any](a))) + * res1: (List[Int], List[Nothing with Any]) = (List(1, 2, 3, 4), List()) + * }}} + */ + def partitionBifoldable[H[_, _], B, C]( + fa: F[A] + )(f: A => H[B, C])(implicit A: Alternative[F], F: Foldable[F], H: Bifoldable[H]): (F[B], F[C]) = { + import cats.syntax.foldable._ + F.partitionBifoldable[H, A, B, C](fa)(f)(A, H) + } + /** * Separate this Foldable into a Tuple by an effectful separating function `A => G[H[B, C]]` for some `Bifoldable[H]` * Equivalent to `Bitraverse#traverse` over `Alternative#separate` @@ -268,6 +289,31 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { final class FoldableOps1[F[_]](private val F: Foldable[F]) extends AnyVal { + /** + * Separate this Foldable into a Tuple by a separating function `A => H[B, C]` for some `Bifoldable[H]` + * Equivalent to `Functor#map` and then `Alternative#separate`. + * + * {{{ + * scala> import cats.implicits._ + * scala> val list = List(1,2,3,4) + * scala> Foldable[List].partitionBifoldable(list)(a => (s"value ${a}", if (a % 2 == 0) -a else a)) + * res0: (List[String], List[Int]) = (List(value 1, value 2, value 3, value 4),List(1, -2, 3, -4)) + * scala> Foldable[List].partitionBifoldable(list)(a => Const[Int, Nothing with Any](a)) + * res1: (List[Int], List[Nothing with Any]) = (List(1, 2, 3, 4),List()) + * }}} + */ + def partitionBifoldable[H[_, _], A, B, C](fa: F[A])(f: A => H[B, C])(implicit A: Alternative[F], + H: Bifoldable[H]): (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.foldMap[A, (F[B], F[C])](fa)( + a => H.bifoldMap[B, C, (F[B], F[C])](f(a))(b => (A.pure(b), A.empty[C]), c => (A.empty[B], A.pure(c))) + ) + } + /** * Separate this Foldable into a Tuple by an effectful separating function `A => G[H[B, C]]` for some `Bifoldable[H]` * Equivalent to `Bitraverse#traverse` over `Alternative#separate` From 6dfb3b4c3a153cf92ff48810757144254813fa19 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Sun, 13 Jan 2019 18:14:04 -0800 Subject: [PATCH 08/17] Typo --- core/src/main/scala/cats/syntax/foldable.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 359d9b6821..49de6457b6 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -265,7 +265,7 @@ final class FoldableOps0[F[_], A](val fa: F[A]) 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` + * Equivalent to `Bitraverse#traverse` over `Alternative#separate` * * {{{ * scala> import cats.implicits._, cats.Eval From 79b7c6f1d26fd67b6b9d3ca95271923b94bbfb91 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Sun, 13 Jan 2019 18:14:18 -0800 Subject: [PATCH 09/17] prePR --- core/src/main/scala/cats/syntax/all.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/syntax/all.scala b/core/src/main/scala/cats/syntax/all.scala index 10f3e2d2ae..2b9e389405 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -85,4 +85,4 @@ trait AllSyntaxBinCompat4 with FoldableSyntaxBinCompat0 with ReducibleSyntaxBinCompat0 with FoldableSyntaxBinCompat1 - with BitraverseSyntaxBinCompat0 \ No newline at end of file + with BitraverseSyntaxBinCompat0 From 3cb7be18b7fb5f2fcac82dcf1bf3eba171b8e5a3 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Sun, 13 Jan 2019 18:22:47 -0800 Subject: [PATCH 10/17] tut fixes --- core/src/main/scala/cats/syntax/foldable.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 49de6457b6..50382fb4bd 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -224,7 +224,7 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { * Equivalent to `Functor#map` over `Alternative#separate` * * {{{ - * scala> import cats.implicits._, cats.Foldable, cats.Eval + * scala> import cats.implicits._, cats.Foldable * scala> val list = List(1,2,3,4) * scala> Foldable[List].partitionBifoldable(list)(a => (a, s"value ${a}")) * res0: (List[Int], List[String]) = (List(1, 2, 3, 4),List(value 1, value 2, value 3, value 4)) @@ -245,7 +245,7 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { * Equivalent to `Bitraverse#traverse` over `Alternative#separate` * * {{{ - * scala> import cats.implicits._, cats.Foldable, cats.Eval + * scala> import cats.implicits._, cats.Foldable * scala> val list = List(1,2,3,4) * scala> val partitioned1 = Foldable[List].partitionBifoldableM(list)(a => (Free.pure((a, s"value ${a}"))): Free[Id, Tuple2[Int, String]]) * Since `Free.pure` yields a deferred computation, we need to force it to inspect the result: @@ -294,7 +294,7 @@ final class FoldableOps1[F[_]](private val F: Foldable[F]) extends AnyVal { * Equivalent to `Functor#map` and then `Alternative#separate`. * * {{{ - * scala> import cats.implicits._ + * scala> import cats.implicits._, cats.Foldable * scala> val list = List(1,2,3,4) * scala> Foldable[List].partitionBifoldable(list)(a => (s"value ${a}", if (a % 2 == 0) -a else a)) * res0: (List[String], List[Int]) = (List(value 1, value 2, value 3, value 4),List(1, -2, 3, -4)) @@ -319,7 +319,7 @@ final class FoldableOps1[F[_]](private val F: Foldable[F]) extends AnyVal { * Equivalent to `Bitraverse#traverse` over `Alternative#separate` * * {{{ - * scala> import cats.implicits._, cats.Foldable, cats.Eval + * scala> import cats.implicits._, cats.Foldable * scala> val list = List(1,2,3,4) * scala> val partitioned1 = Foldable[List].partitionBifoldableM(list)(a => (Free.pure((a, s"value ${a}"))): Free[Id, Tuple2[Int, String]]) * Since `Free.pure` yields a deferred computation, we need to force it to inspect the result: From cc7275d0cefbc1394d30e599800a61f80a986a37 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Sun, 13 Jan 2019 18:46:42 -0800 Subject: [PATCH 11/17] Accidentally shadowed fa --- core/src/main/scala/cats/syntax/foldable.scala | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 50382fb4bd..af91b159ad 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -233,9 +233,7 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { * res1: (List[Int], List[Nothing with Any]) = (List(1, 2, 3, 4), List()) * }}} */ - def partitionBifoldable[H[_, _], B, C]( - fa: F[A] - )(f: A => H[B, C])(implicit A: Alternative[F], F: Foldable[F], H: Bifoldable[H]): (F[B], F[C]) = { + def partitionBifoldable[H[_, _], B, C](f: A => H[B, C])(implicit A: Alternative[F], F: Foldable[F], H: Bifoldable[H]): (F[B], F[C]) = { import cats.syntax.foldable._ F.partitionBifoldable[H, A, B, C](fa)(f)(A, H) } @@ -256,9 +254,7 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { * res1: (List[Int], List[Nothing with Any]) = (List(1, 2, 3, 4), List()) * }}} */ - def partitionBifoldableM[G[_], H[_, _], B, C]( - fa: F[A] - )(f: A => G[H[B, C]])(implicit A: Alternative[F], F: Foldable[F], M: Monad[G], H: Bifoldable[H]): G[(F[B], F[C])] = { + def partitionBifoldableM[G[_], H[_, _], B, C](f: A => G[H[B, C]])(implicit A: Alternative[F], F: Foldable[F], M: Monad[G], H: Bifoldable[H]): G[(F[B], F[C])] = { import cats.syntax.foldable._ F.partitionBifoldableM[G, H, A, B, C](fa)(f)(A, M, H) } From b3fb6d361befd24d6f24b9c52cf0f7baa21d9981 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Sun, 13 Jan 2019 18:46:58 -0800 Subject: [PATCH 12/17] Incorrectly referenced Bitraverse --- core/src/main/scala/cats/syntax/foldable.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index af91b159ad..aea0679c76 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -240,7 +240,7 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { /** * Separate this Foldable into a Tuple by an effectful separating function `A => G[H[B, C]]` for some `Bifoldable[H]` - * Equivalent to `Bitraverse#traverse` over `Alternative#separate` + * Equivalent to `Traverse#traverse` over `Alternative#separate` * * {{{ * scala> import cats.implicits._, cats.Foldable @@ -261,7 +261,7 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { /** * Separate this Foldable into a Tuple by an effectful separating function `A => G[Either[B, C]]` - * Equivalent to `Bitraverse#traverse` over `Alternative#separate` + * Equivalent to `Traverse#traverse` over `Alternative#separate` * * {{{ * scala> import cats.implicits._, cats.Eval @@ -312,7 +312,7 @@ final class FoldableOps1[F[_]](private val F: Foldable[F]) extends AnyVal { /** * Separate this Foldable into a Tuple by an effectful separating function `A => G[H[B, C]]` for some `Bifoldable[H]` - * Equivalent to `Bitraverse#traverse` over `Alternative#separate` + * Equivalent to `Traverse#traverse` over `Alternative#separate` * * {{{ * scala> import cats.implicits._, cats.Foldable @@ -344,7 +344,7 @@ final class FoldableOps1[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 `Bitraverse#traverse` over `Alternative#separate` + * Equivalent to `Traverse#traverse` over `Alternative#separate` * * {{{ * scala> import cats.implicits._, cats.Foldable, cats.Eval From 95ab3862642ca490eb20ef2677010591af7a3dfa Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Thu, 17 Jan 2019 12:15:06 -0800 Subject: [PATCH 13/17] prePR --- core/src/main/scala/cats/syntax/foldable.scala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index aea0679c76..7e196b1607 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -233,7 +233,9 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { * res1: (List[Int], List[Nothing with Any]) = (List(1, 2, 3, 4), List()) * }}} */ - def partitionBifoldable[H[_, _], B, C](f: A => H[B, C])(implicit A: Alternative[F], F: Foldable[F], H: Bifoldable[H]): (F[B], F[C]) = { + def partitionBifoldable[H[_, _], B, C]( + f: A => H[B, C] + )(implicit A: Alternative[F], F: Foldable[F], H: Bifoldable[H]): (F[B], F[C]) = { import cats.syntax.foldable._ F.partitionBifoldable[H, A, B, C](fa)(f)(A, H) } @@ -254,7 +256,9 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { * res1: (List[Int], List[Nothing with Any]) = (List(1, 2, 3, 4), List()) * }}} */ - def partitionBifoldableM[G[_], H[_, _], B, C](f: A => G[H[B, C]])(implicit A: Alternative[F], F: Foldable[F], M: Monad[G], H: Bifoldable[H]): G[(F[B], F[C])] = { + def partitionBifoldableM[G[_], H[_, _], B, C]( + f: A => G[H[B, C]] + )(implicit A: Alternative[F], F: Foldable[F], M: Monad[G], H: Bifoldable[H]): G[(F[B], F[C])] = { import cats.syntax.foldable._ F.partitionBifoldableM[G, H, A, B, C](fa)(f)(A, M, H) } From 7f9923f3eb08af3607586335610ed0c0620d578f Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Fri, 18 Jan 2019 07:39:54 -0800 Subject: [PATCH 14/17] More doctest fixes --- .../src/main/scala/cats/syntax/foldable.scala | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 7e196b1607..32c8790f14 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -224,12 +224,12 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { * Equivalent to `Functor#map` over `Alternative#separate` * * {{{ - * scala> import cats.implicits._, cats.Foldable + * scala> import cats.implicits._, cats.data.Const * scala> val list = List(1,2,3,4) - * scala> Foldable[List].partitionBifoldable(list)(a => (a, s"value ${a}")) + * scala> list.partitionBifoldable(a => (a, s"value ${a}")) * res0: (List[Int], List[String]) = (List(1, 2, 3, 4),List(value 1, value 2, value 3, value 4)) * `Const`'s second parameter is never instantiated, so we can use an impossible type: - * scala> Foldable[List].partitionBifoldable(list)(a => Option(Const[Int, Nothing with Any](a))) + * scala> list.partitionBifoldable(a => Const[Int, Nothing with Any](a)) * res1: (List[Int], List[Nothing with Any]) = (List(1, 2, 3, 4), List()) * }}} */ @@ -245,15 +245,11 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { * Equivalent to `Traverse#traverse` over `Alternative#separate` * * {{{ - * scala> import cats.implicits._, cats.Foldable + * scala> import cats.implicits._, cats.data.Const * scala> val list = List(1,2,3,4) - * scala> val partitioned1 = Foldable[List].partitionBifoldableM(list)(a => (Free.pure((a, s"value ${a}"))): Free[Id, Tuple2[Int, String]]) - * Since `Free.pure` yields a deferred computation, we need to force it to inspect the result: - * scala> partitioned1.run - * res0: (List[Int], List[String]) = (List(1, 2, 3, 4),List(value 1, value 2, value 3, value 4)) * `Const`'s second parameter is never instantiated, so we can use an impossible type: - * scala> Foldable[List].partitionEitherM(list)(a => Option(Const[Int, Nothing with Any](a))) - * res1: (List[Int], List[Nothing with Any]) = (List(1, 2, 3, 4), List()) + * scala> list.partitionBifoldableM(a => Option(Const[Int, Nothing with Any](a))) + * res0: Option[(List[Int], List[Nothing with Any])] = Some((List(1, 2, 3, 4), List())) * }}} */ def partitionBifoldableM[G[_], H[_, _], B, C]( @@ -294,7 +290,7 @@ final class FoldableOps1[F[_]](private val F: Foldable[F]) extends AnyVal { * Equivalent to `Functor#map` and then `Alternative#separate`. * * {{{ - * scala> import cats.implicits._, cats.Foldable + * scala> import cats.implicits._, cats.Foldable, cats.data.Const * scala> val list = List(1,2,3,4) * scala> Foldable[List].partitionBifoldable(list)(a => (s"value ${a}", if (a % 2 == 0) -a else a)) * res0: (List[String], List[Int]) = (List(value 1, value 2, value 3, value 4),List(1, -2, 3, -4)) @@ -319,15 +315,11 @@ final class FoldableOps1[F[_]](private val F: Foldable[F]) extends AnyVal { * Equivalent to `Traverse#traverse` over `Alternative#separate` * * {{{ - * scala> import cats.implicits._, cats.Foldable + * scala> import cats.implicits._, cats.Foldable, cats.data.Const * scala> val list = List(1,2,3,4) - * scala> val partitioned1 = Foldable[List].partitionBifoldableM(list)(a => (Free.pure((a, s"value ${a}"))): Free[Id, Tuple2[Int, String]]) - * Since `Free.pure` yields a deferred computation, we need to force it to inspect the result: - * scala> partitioned1.run - * res0: (List[Int], List[String]) = (List(1, 2, 3, 4),List(value 1, value 2, value 3, value 4)) * `Const`'s second parameter is never instantiated, so we can use an impossible type: - * scala> Foldable[List].partitionEitherM(list)(a => Option(Const[Int, Nothing with Any](a))) - * res1: (List[Int], List[Nothing with Any]) = (List(1, 2, 3, 4), List()) + * scala> Foldable[List].partitionBifoldableM(list)(a => Option(Const[Int, Nothing with Any](a))) + * res0: Option[(List[Int], List[Nothing with Any])] = Some((List(1, 2, 3, 4), List())) * }}} */ def partitionBifoldableM[G[_], H[_, _], A, B, C]( From bd8f0cb5089aa034e083599c6fc67e6fb6f5edfa Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Fri, 18 Jan 2019 07:40:33 -0800 Subject: [PATCH 15/17] partitionBifoldable* -> partitionBifold* --- .../src/main/scala/cats/syntax/foldable.scala | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 32c8790f14..04db234f5f 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -226,18 +226,18 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { * {{{ * scala> import cats.implicits._, cats.data.Const * scala> val list = List(1,2,3,4) - * scala> list.partitionBifoldable(a => (a, s"value ${a}")) + * scala> list.partitionBifold(a => (a, s"value ${a}")) * res0: (List[Int], List[String]) = (List(1, 2, 3, 4),List(value 1, value 2, value 3, value 4)) * `Const`'s second parameter is never instantiated, so we can use an impossible type: - * scala> list.partitionBifoldable(a => Const[Int, Nothing with Any](a)) + * scala> list.partitionBifold(a => Const[Int, Nothing with Any](a)) * res1: (List[Int], List[Nothing with Any]) = (List(1, 2, 3, 4), List()) * }}} */ - def partitionBifoldable[H[_, _], B, C]( + def partitionBifold[H[_, _], B, C]( f: A => H[B, C] )(implicit A: Alternative[F], F: Foldable[F], H: Bifoldable[H]): (F[B], F[C]) = { import cats.syntax.foldable._ - F.partitionBifoldable[H, A, B, C](fa)(f)(A, H) + F.partitionBifold[H, A, B, C](fa)(f)(A, H) } /** @@ -248,15 +248,15 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { * scala> import cats.implicits._, cats.data.Const * scala> val list = List(1,2,3,4) * `Const`'s second parameter is never instantiated, so we can use an impossible type: - * scala> list.partitionBifoldableM(a => Option(Const[Int, Nothing with Any](a))) + * scala> list.partitionBifoldM(a => Option(Const[Int, Nothing with Any](a))) * res0: Option[(List[Int], List[Nothing with Any])] = Some((List(1, 2, 3, 4), List())) * }}} */ - def partitionBifoldableM[G[_], H[_, _], B, C]( + def partitionBifoldM[G[_], H[_, _], B, C]( f: A => G[H[B, C]] )(implicit A: Alternative[F], F: Foldable[F], M: Monad[G], H: Bifoldable[H]): G[(F[B], F[C])] = { import cats.syntax.foldable._ - F.partitionBifoldableM[G, H, A, B, C](fa)(f)(A, M, H) + F.partitionBifoldM[G, H, A, B, C](fa)(f)(A, M, H) } /** @@ -292,13 +292,13 @@ final class FoldableOps1[F[_]](private val F: Foldable[F]) extends AnyVal { * {{{ * scala> import cats.implicits._, cats.Foldable, cats.data.Const * scala> val list = List(1,2,3,4) - * scala> Foldable[List].partitionBifoldable(list)(a => (s"value ${a}", if (a % 2 == 0) -a else a)) + * scala> Foldable[List].partitionBifold(list)(a => (s"value ${a}", if (a % 2 == 0) -a else a)) * res0: (List[String], List[Int]) = (List(value 1, value 2, value 3, value 4),List(1, -2, 3, -4)) - * scala> Foldable[List].partitionBifoldable(list)(a => Const[Int, Nothing with Any](a)) + * scala> Foldable[List].partitionBifold(list)(a => Const[Int, Nothing with Any](a)) * res1: (List[Int], List[Nothing with Any]) = (List(1, 2, 3, 4),List()) * }}} */ - def partitionBifoldable[H[_, _], A, B, C](fa: F[A])(f: A => H[B, C])(implicit A: Alternative[F], + def partitionBifold[H[_, _], A, B, C](fa: F[A])(f: A => H[B, C])(implicit A: Alternative[F], H: Bifoldable[H]): (F[B], F[C]) = { import cats.instances.tuple._ @@ -318,11 +318,11 @@ final class FoldableOps1[F[_]](private val F: Foldable[F]) extends AnyVal { * scala> import cats.implicits._, cats.Foldable, cats.data.Const * scala> val list = List(1,2,3,4) * `Const`'s second parameter is never instantiated, so we can use an impossible type: - * scala> Foldable[List].partitionBifoldableM(list)(a => Option(Const[Int, Nothing with Any](a))) + * scala> Foldable[List].partitionBifoldM(list)(a => Option(Const[Int, Nothing with Any](a))) * res0: Option[(List[Int], List[Nothing with Any])] = Some((List(1, 2, 3, 4), List())) * }}} */ - def partitionBifoldableM[G[_], H[_, _], A, B, C]( + def partitionBifoldM[G[_], H[_, _], A, B, C]( fa: F[A] )(f: A => G[H[B, C]])(implicit A: Alternative[F], M: Monad[G], H: Bifoldable[H]): G[(F[B], F[C])] = { import cats.instances.tuple._ @@ -357,6 +357,6 @@ final class FoldableOps1[F[_]](private val F: Foldable[F]) extends AnyVal { 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.either._ - partitionBifoldableM[G, Either, A, B, C](fa)(f)(A, M, Bifoldable[Either]) + partitionBifoldM[G, Either, A, B, C](fa)(f)(A, M, Bifoldable[Either]) } } From f4eef2315f9816bd4e8c31f6b1c4de5994c65b89 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Fri, 18 Jan 2019 08:20:04 -0800 Subject: [PATCH 16/17] fmt --- core/src/main/scala/cats/syntax/foldable.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 04db234f5f..2489d45f00 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -299,7 +299,7 @@ final class FoldableOps1[F[_]](private val F: Foldable[F]) extends AnyVal { * }}} */ def partitionBifold[H[_, _], A, B, C](fa: F[A])(f: A => H[B, C])(implicit A: Alternative[F], - H: Bifoldable[H]): (F[B], F[C]) = { + H: Bifoldable[H]): (F[B], F[C]) = { import cats.instances.tuple._ implicit val mb: Monoid[F[B]] = A.algebra[B] From 43e4276c5d3d9eb0711a3219346958a4385b5e52 Mon Sep 17 00:00:00 2001 From: Devon Stewart Date: Fri, 18 Jan 2019 08:59:22 -0800 Subject: [PATCH 17/17] Doctest fixes --- core/src/main/scala/cats/syntax/foldable.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 2489d45f00..a72415b2f0 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -226,7 +226,7 @@ final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { * {{{ * scala> import cats.implicits._, cats.data.Const * scala> val list = List(1,2,3,4) - * scala> list.partitionBifold(a => (a, s"value ${a}")) + * scala> list.partitionBifold(a => (a, "value " + a.toString)) * res0: (List[Int], List[String]) = (List(1, 2, 3, 4),List(value 1, value 2, value 3, value 4)) * `Const`'s second parameter is never instantiated, so we can use an impossible type: * scala> list.partitionBifold(a => Const[Int, Nothing with Any](a)) @@ -292,7 +292,7 @@ final class FoldableOps1[F[_]](private val F: Foldable[F]) extends AnyVal { * {{{ * scala> import cats.implicits._, cats.Foldable, cats.data.Const * scala> val list = List(1,2,3,4) - * scala> Foldable[List].partitionBifold(list)(a => (s"value ${a}", if (a % 2 == 0) -a else a)) + * scala> Foldable[List].partitionBifold(list)(a => ("value " + a.toString(), if (a % 2 == 0) -a else a)) * res0: (List[String], List[Int]) = (List(value 1, value 2, value 3, value 4),List(1, -2, 3, -4)) * scala> Foldable[List].partitionBifold(list)(a => Const[Int, Nothing with Any](a)) * res1: (List[Int], List[Nothing with Any]) = (List(1, 2, 3, 4),List())