From 2ce81ea68e37d50a780edf810d2da3e5ef12c612 Mon Sep 17 00:00:00 2001 From: Maxim Davydov Date: Thu, 14 Nov 2019 14:58:52 +0300 Subject: [PATCH 01/14] #3141 [WIP] Implemented .foldA --- core/src/main/scala/cats/Foldable.scala | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index 190ac117a6..38bcfc8fa7 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -278,6 +278,26 @@ import Foldable.sentinel } } + /** + * Fold implemented using the given `Applicative[G]` and `Monoid[A]` instance. + * + * This method is identical to fold, except that we use `Applicative[G]` and `Monoid[A]` + * to combine a's inside an applicative G. + * + * For example: + * + * {{{ + * scala> import cats.implicits._ + * scala> val F = Foldable[List] + * scala> F.foldA(List(Right(1) :: Right(2) :: Nil) + * res0: Right[Int] = Right(3) + * }}} + */ + def foldA[G[_], A](fga: F[G[A]])(implicit G: Applicative[G], A: Monoid[A]): G[A] = + foldLeft(fga, G.pure(A.empty)) { (acc, ga) => + G.map2(acc, ga)(A.combine) + } + /** * Alias for [[foldM]]. */ From ac9efdca41fc20f121312a3f49b379d4ddc1c2be Mon Sep 17 00:00:00 2001 From: Maxim Davydov Date: Thu, 14 Nov 2019 14:59:27 +0300 Subject: [PATCH 02/14] #3141 [WIP] Implemented .reduceA --- core/src/main/scala/cats/Reducible.scala | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/src/main/scala/cats/Reducible.scala b/core/src/main/scala/cats/Reducible.scala index 99b2e7fa71..c77b20b7de 100644 --- a/core/src/main/scala/cats/Reducible.scala +++ b/core/src/main/scala/cats/Reducible.scala @@ -66,6 +66,15 @@ import simulacrum.typeclass def reduceLeftM[G[_], A, B](fa: F[A])(f: A => G[B])(g: (B, A) => G[B])(implicit G: FlatMap[G]): G[B] = reduceLeftTo(fa)(f)((gb, a) => G.flatMap(gb)(g(_, a))) + /** + * Reduce a `F[G[A]]` value using `Applicative[G]` and `Semigroup[A]`, a universal + * semigroup for `G[_]`. + * + * This method is a generalization of `reduce`. + */ + def reduceA[G[_], A](fga: F[G[A]])(implicit G: Applicative[G], A: Semigroup[A]): G[A] = + reduceLeft(fga)((ga1, ga2) => G.map2(ga1, ga2)(A.combine)) + /** * Monadic reducing by mapping the `A` values to `G[B]`. combining * the `B` values using the given `Semigroup[B]` instance. From 6d28b9caf1932bbef89cca82f7261cecf1616ec2 Mon Sep 17 00:00:00 2001 From: Maxim Davydov Date: Thu, 14 Nov 2019 14:59:38 +0300 Subject: [PATCH 03/14] #3141 [WIP] Implemented .reduceMapA --- core/src/main/scala/cats/Reducible.scala | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/main/scala/cats/Reducible.scala b/core/src/main/scala/cats/Reducible.scala index c77b20b7de..41e136039f 100644 --- a/core/src/main/scala/cats/Reducible.scala +++ b/core/src/main/scala/cats/Reducible.scala @@ -75,6 +75,13 @@ import simulacrum.typeclass def reduceA[G[_], A](fga: F[G[A]])(implicit G: Applicative[G], A: Semigroup[A]): G[A] = reduceLeft(fga)((ga1, ga2) => G.map2(ga1, ga2)(A.combine)) + /** + * Apply `f` to each applicative `ga` of `fga` and combine them using the + * given `Semigroup[B]`. + */ + def reduceMapA[G[_], A, B](fga: F[G[A]])(f: A => B)(implicit G: Applicative[G], B: Semigroup[B]): G[B] = + reduceLeftTo(fga)(ga => G.map(ga)(f))((gb, ga) => G.map2(gb, G.map(ga)(f))(B.combine)) + /** * Monadic reducing by mapping the `A` values to `G[B]`. combining * the `B` values using the given `Semigroup[B]` instance. From f914fb53115939f8148bfad83fc9ad619c43e117 Mon Sep 17 00:00:00 2001 From: Maxim Davydov Date: Fri, 15 Nov 2019 16:44:00 +0300 Subject: [PATCH 04/14] #3141 Refactored --- core/src/main/scala/cats/Foldable.scala | 36 +++++++++---------- core/src/main/scala/cats/Reducible.scala | 22 ++++++------ .../src/main/scala/cats/syntax/foldable.scala | 3 ++ .../main/scala/cats/syntax/reducible.scala | 6 ++++ 4 files changed, 36 insertions(+), 31 deletions(-) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index 38bcfc8fa7..3ee4dffa7b 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -3,7 +3,7 @@ package cats import scala.collection.mutable import cats.instances.either._ import cats.kernel.CommutativeMonoid -import simulacrum.typeclass +import simulacrum.{noop, typeclass} import Foldable.sentinel /** @@ -279,24 +279,22 @@ import Foldable.sentinel } /** - * Fold implemented using the given `Applicative[G]` and `Monoid[A]` instance. - * - * This method is identical to fold, except that we use `Applicative[G]` and `Monoid[A]` - * to combine a's inside an applicative G. - * - * For example: - * - * {{{ - * scala> import cats.implicits._ - * scala> val F = Foldable[List] - * scala> F.foldA(List(Right(1) :: Right(2) :: Nil) - * res0: Right[Int] = Right(3) - * }}} - */ - def foldA[G[_], A](fga: F[G[A]])(implicit G: Applicative[G], A: Monoid[A]): G[A] = - foldLeft(fga, G.pure(A.empty)) { (acc, ga) => - G.map2(acc, ga)(A.combine) - } + * Fold implemented using the given `Applicative[G]` and `Monoid[A]` instance. + * + * This method is identical to fold, except that we use `Applicative[G]` and `Monoid[A]` + * to combine a's inside an applicative G. + * + * For example: + * + * {{{ + * scala> import cats.implicits._ + * scala> val F = Foldable[List] + * scala> F.foldA(List(Right(1) :: Right(2) :: Nil) + * res0: Right[Int] = Right(3) + * }}} + */ + @noop def foldA[G[_], A](fga: F[G[A]])(implicit G: Applicative[G], A: Monoid[A]): G[A] = + fold(fga)(Applicative.monoid) /** * Alias for [[foldM]]. diff --git a/core/src/main/scala/cats/Reducible.scala b/core/src/main/scala/cats/Reducible.scala index 41e136039f..d61bf636b9 100644 --- a/core/src/main/scala/cats/Reducible.scala +++ b/core/src/main/scala/cats/Reducible.scala @@ -1,7 +1,7 @@ package cats import cats.data.{Ior, NonEmptyList} -import simulacrum.typeclass +import simulacrum.{noop, typeclass} /** * Data structures that can be reduced to a summary value. @@ -67,19 +67,17 @@ import simulacrum.typeclass reduceLeftTo(fa)(f)((gb, a) => G.flatMap(gb)(g(_, a))) /** - * Reduce a `F[G[A]]` value using `Applicative[G]` and `Semigroup[A]`, a universal - * semigroup for `G[_]`. - * - * This method is a generalization of `reduce`. - */ - def reduceA[G[_], A](fga: F[G[A]])(implicit G: Applicative[G], A: Semigroup[A]): G[A] = - reduceLeft(fga)((ga1, ga2) => G.map2(ga1, ga2)(A.combine)) + * Reduce a `F[G[A]]` value using `Applicative[G]` and `Semigroup[A]`, a universal + * semigroup for `G[_]`. + */ + @noop def reduceA[G[_], A](fga: F[G[A]])(implicit G: Apply[G], A: Semigroup[A]): G[A] = + reduce(fga)(Apply.semigroup) /** - * Apply `f` to each applicative `ga` of `fga` and combine them using the - * given `Semigroup[B]`. - */ - def reduceMapA[G[_], A, B](fga: F[G[A]])(f: A => B)(implicit G: Applicative[G], B: Semigroup[B]): G[B] = + * Apply `f` to each applicative `ga` of `fga` and combine them using the + * given `Semigroup[B]`. + */ + @noop def reduceMapA[G[_], A, B](fga: F[G[A]])(f: A => B)(implicit G: Apply[G], B: Semigroup[B]): G[B] = reduceLeftTo(fga)(ga => G.map(ga)(f))((gb, ga) => G.map2(gb, G.map(ga)(f))(B.combine)) /** diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 53157f0c99..9815f0d2c8 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -44,6 +44,9 @@ final class FoldableOps[F[_], A](private val fa: F[A]) extends AnyVal { def foldr[B](b: Eval[B])(f: (A, Eval[B]) => Eval[B])(implicit F: Foldable[F]): Eval[B] = F.foldRight(fa, b)(f) + def foldA[G[_], B](implicit F: Foldable[F], ev: A <:< G[B], G: Applicative[G], B: Monoid[B]): G[B] = + F.foldA[G, B](fa.asInstanceOf[F[G[B]]]) + /** * test if `F[A]` contains an `A`, named contains_ to avoid conflict with existing contains which uses universal equality * diff --git a/core/src/main/scala/cats/syntax/reducible.scala b/core/src/main/scala/cats/syntax/reducible.scala index 3e5904ef52..42cc8dda62 100644 --- a/core/src/main/scala/cats/syntax/reducible.scala +++ b/core/src/main/scala/cats/syntax/reducible.scala @@ -31,4 +31,10 @@ final class ReducibleOps0[F[_], A](private val fa: F[A]) extends AnyVal { * */ def reduceMapK[G[_], B](f: A => G[B])(implicit F: Reducible[F], G: SemigroupK[G]): G[B] = F.reduceLeftTo(fa)(f)((b, a) => G.combineK(b, f(a))) + + def reduceA[G[_], B](implicit F: Reducible[F], ev: A <:< G[B], G: Apply[G], B: Semigroup[B]): G[B] = + F.reduceA[G, B](fa.asInstanceOf[F[G[B]]]) + + def reduceMapA[G[_], B, C](f: B => C)(implicit F: Reducible[F], ev: A <:< G[B], G: Apply[G], C: Semigroup[C]): G[C] = + F.reduceMapA[G, B, C](fa.asInstanceOf[F[G[B]]])(f) } From aa362271b1d13c47c249014b54d9c5ed1b90db3a Mon Sep 17 00:00:00 2001 From: Maxim Davydov Date: Fri, 15 Nov 2019 16:45:33 +0300 Subject: [PATCH 05/14] #3141 Added tests --- .../cats/tests/NonEmptyStreamSuite.scala | 3 ++ .../test/scala/cats/tests/FoldableSuite.scala | 14 +++++++++ .../scala/cats/tests/NonEmptyChainSuite.scala | 3 ++ .../scala/cats/tests/NonEmptyListSuite.scala | 2 ++ .../cats/tests/NonEmptyVectorSuite.scala | 3 ++ .../scala/cats/tests/ReducibleSuite.scala | 31 +++++++++++++++++++ 6 files changed, 56 insertions(+) diff --git a/tests/src/test/scala-2.12/cats/tests/NonEmptyStreamSuite.scala b/tests/src/test/scala-2.12/cats/tests/NonEmptyStreamSuite.scala index 33774472eb..7546ebf21b 100644 --- a/tests/src/test/scala-2.12/cats/tests/NonEmptyStreamSuite.scala +++ b/tests/src/test/scala-2.12/cats/tests/NonEmptyStreamSuite.scala @@ -166,4 +166,7 @@ class ReducibleNonEmptyStreamSuite extends ReducibleSuite[NonEmptyStream]("NonEm val tailStart: Long = start + 1L NonEmptyStream(start, tailStart.to(endInclusive).toStream) } + + def rangeE[L, R](el: Either[L, R], els: Either[L, R]*): NonEmptyStream[Either[L, R]] = + NonEmptyStream(el, Stream(els: _*)) } diff --git a/tests/src/test/scala/cats/tests/FoldableSuite.scala b/tests/src/test/scala/cats/tests/FoldableSuite.scala index 5080fff6ca..be32f67d7a 100644 --- a/tests/src/test/scala/cats/tests/FoldableSuite.scala +++ b/tests/src/test/scala/cats/tests/FoldableSuite.scala @@ -409,6 +409,20 @@ class FoldableSuiteAdditional extends CatsSuite with ScalaVersionSpecificFoldabl Foldable[Stream].foldRight(fa, lb)(f) } + test(".foldA successful case") { + implicit val F = foldableStreamWithDefaultImpl + val ns = Stream.apply[Either[String, Int]](1.asRight, 2.asRight, 7.asRight) + + assert(F.foldA(ns) == 10.asRight[String]) + } + + test(".foldA failed case") { + implicit val F = foldableStreamWithDefaultImpl + val ns = Stream.apply[Either[String, Int]](1.asRight, "boom!!!".asLeft, 7.asRight) + + assert(ns.foldA == "boom!!!".asLeft[Int]) + } + test(".foldLeftM short-circuiting") { implicit val F = foldableStreamWithDefaultImpl val ns = Stream.continually(1) diff --git a/tests/src/test/scala/cats/tests/NonEmptyChainSuite.scala b/tests/src/test/scala/cats/tests/NonEmptyChainSuite.scala index 2d76aa261b..bd39b96bcc 100644 --- a/tests/src/test/scala/cats/tests/NonEmptyChainSuite.scala +++ b/tests/src/test/scala/cats/tests/NonEmptyChainSuite.scala @@ -158,4 +158,7 @@ class ReducibleNonEmptyChainSuite extends ReducibleSuite[NonEmptyChain]("NonEmpt def range(start: Long, endInclusive: Long): NonEmptyChain[Long] = NonEmptyChain(start, (start + 1L).to(endInclusive): _*) + + def rangeE[L, R](el: Either[L, R], els: Either[L, R]*): NonEmptyChain[Either[L, R]] = + NonEmptyChain(el, els: _*) } diff --git a/tests/src/test/scala/cats/tests/NonEmptyListSuite.scala b/tests/src/test/scala/cats/tests/NonEmptyListSuite.scala index b26c6ba674..0a50bcf905 100644 --- a/tests/src/test/scala/cats/tests/NonEmptyListSuite.scala +++ b/tests/src/test/scala/cats/tests/NonEmptyListSuite.scala @@ -366,4 +366,6 @@ class ReducibleNonEmptyListSuite extends ReducibleSuite[NonEmptyList]("NonEmptyL NonEmptyList(start, (tailStart).to(endInclusive).toList) } + def rangeE[L, R](el: Either[L, R], els: Either[L, R]*): NonEmptyList[Either[L, R]] = + NonEmptyList(el, List(els: _*)) } diff --git a/tests/src/test/scala/cats/tests/NonEmptyVectorSuite.scala b/tests/src/test/scala/cats/tests/NonEmptyVectorSuite.scala index 226c809dd0..ca0e522476 100644 --- a/tests/src/test/scala/cats/tests/NonEmptyVectorSuite.scala +++ b/tests/src/test/scala/cats/tests/NonEmptyVectorSuite.scala @@ -399,4 +399,7 @@ class ReducibleNonEmptyVectorSuite extends ReducibleSuite[NonEmptyVector]("NonEm val tailStart: Long = start + 1L NonEmptyVector(start, (tailStart).to(endInclusive).toVector) } + + def rangeE[L, R](el: Either[L, R], els: Either[L, R]*): NonEmptyVector[Either[L, R]] = + NonEmptyVector(el, Vector(els: _*)) } diff --git a/tests/src/test/scala/cats/tests/ReducibleSuite.scala b/tests/src/test/scala/cats/tests/ReducibleSuite.scala index d5afd6f4bc..f22e05334c 100644 --- a/tests/src/test/scala/cats/tests/ReducibleSuite.scala +++ b/tests/src/test/scala/cats/tests/ReducibleSuite.scala @@ -77,6 +77,7 @@ abstract class ReducibleSuite[F[_]: Reducible](name: String)(implicit ArbFInt: A extends FoldableSuite[F](name) { def range(start: Long, endInclusive: Long): F[Long] + def rangeE[L, R](el: Either[L, R], els: Either[L, R]*): F[Either[L, R]] test(s"Reducible[$name].reduceLeftM stack safety") { def nonzero(acc: Long, x: Long): Option[Long] = @@ -88,6 +89,36 @@ abstract class ReducibleSuite[F[_]: Reducible](name: String)(implicit ArbFInt: A actual should ===(Some(expected)) } + test(s"Reducible[$name].reduceA successful case") { + val expected = 6 + val actual = rangeE(1.asRight[String], 2.asRight[String], 3.asRight[String]).reduceA + actual should ===(expected.asRight[String]) + } + + test(s"Reducible[$name].reduceA failure case") { + val expected = "boom!!!" + val actual = rangeE(1.asRight, "boom!!!".asLeft, 3.asRight).reduceA + actual should ===(expected.asLeft[Int]) + } + + test(s"Reducible[$name].reduceMapA successful case") { + def intToString(i: Int): String = i.toString + + val expected = "123" + val actual = + rangeE(1.asRight[String], 2.asRight[String], 3.asRight[String]).reduceMapA(intToString) + + actual should ===(expected.asRight[String]) + } + + test(s"Reducible[$name].reduceMapA failure case") { + def intToString(i: Int): String = i.toString + + val expected = "boom!!!" + val actual = rangeE(1.asRight, "boom!!!".asLeft, 3.asRight).reduceMapA(intToString) + actual should ===(expected.asLeft[String]) + } + test(s"Reducible[$name].toNonEmptyList/toList consistency") { forAll { fa: F[Int] => fa.toList.toNel should ===(Some(fa.toNonEmptyList)) From ae5a3d71dc6aea78b831f3ba28f8c939060d65d7 Mon Sep 17 00:00:00 2001 From: Maxim Davydov Date: Fri, 15 Nov 2019 16:56:36 +0300 Subject: [PATCH 06/14] #3141 Fixed 2.13 --- .../test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/src/test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala b/tests/src/test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala index 26edbf10cd..8450eb3bcf 100644 --- a/tests/src/test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala +++ b/tests/src/test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala @@ -134,4 +134,7 @@ class ReducibleNonEmptyLazyListSuite extends ReducibleSuite[NonEmptyLazyList]("N def range(start: Long, endInclusive: Long): NonEmptyLazyList[Long] = NonEmptyLazyList(start, (start + 1L).to(endInclusive): _*) + + def rangeE[L, R](el: Either[L, R], els: Either[L, R]*): NonEmptyLazyList[Either[L, R]] = + NonEmptyLazyList(el, els: _*) } From 1ff4848d1561e6d7e58d66c5f0485d8f97404991 Mon Sep 17 00:00:00 2001 From: Maxim Davydov Date: Fri, 15 Nov 2019 17:00:54 +0300 Subject: [PATCH 07/14] #3141 Added link to the issue at simulacrum --- core/src/main/scala/cats/Foldable.scala | 2 ++ core/src/main/scala/cats/Reducible.scala | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index 3ee4dffa7b..dd3f0931fb 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -292,6 +292,8 @@ import Foldable.sentinel * scala> F.foldA(List(Right(1) :: Right(2) :: Nil) * res0: Right[Int] = Right(3) * }}} + * + * `noop` usage description [[https://github.com/typelevel/simulacrum/issues/162 here]] */ @noop def foldA[G[_], A](fga: F[G[A]])(implicit G: Applicative[G], A: Monoid[A]): G[A] = fold(fga)(Applicative.monoid) diff --git a/core/src/main/scala/cats/Reducible.scala b/core/src/main/scala/cats/Reducible.scala index d61bf636b9..819aee70a2 100644 --- a/core/src/main/scala/cats/Reducible.scala +++ b/core/src/main/scala/cats/Reducible.scala @@ -69,6 +69,8 @@ import simulacrum.{noop, typeclass} /** * Reduce a `F[G[A]]` value using `Applicative[G]` and `Semigroup[A]`, a universal * semigroup for `G[_]`. + * + * `noop` usage description [[https://github.com/typelevel/simulacrum/issues/162 here]] */ @noop def reduceA[G[_], A](fga: F[G[A]])(implicit G: Apply[G], A: Semigroup[A]): G[A] = reduce(fga)(Apply.semigroup) @@ -76,6 +78,8 @@ import simulacrum.{noop, typeclass} /** * Apply `f` to each applicative `ga` of `fga` and combine them using the * given `Semigroup[B]`. + * + * `noop` usage description [[https://github.com/typelevel/simulacrum/issues/162 here]] */ @noop def reduceMapA[G[_], A, B](fga: F[G[A]])(f: A => B)(implicit G: Apply[G], B: Semigroup[B]): G[B] = reduceLeftTo(fga)(ga => G.map(ga)(f))((gb, ga) => G.map2(gb, G.map(ga)(f))(B.combine)) From 07f8d3874460a2551cf0d01473b96acb22746212 Mon Sep 17 00:00:00 2001 From: Maxim Davydov Date: Fri, 15 Nov 2019 18:38:24 +0300 Subject: [PATCH 08/14] #3141 Fixed docs --- core/src/main/scala/cats/Foldable.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index dd3f0931fb..54f60408fd 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -289,8 +289,8 @@ import Foldable.sentinel * {{{ * scala> import cats.implicits._ * scala> val F = Foldable[List] - * scala> F.foldA(List(Right(1) :: Right(2) :: Nil) - * res0: Right[Int] = Right(3) + * scala> F.foldA(List(Either.right[String, Int](1), Either.right[String, Int](2))) + * res0: Either[String, Int] = Right(3) * }}} * * `noop` usage description [[https://github.com/typelevel/simulacrum/issues/162 here]] From d59858ad95fa1cd62076d139f4d45e2ca299ea02 Mon Sep 17 00:00:00 2001 From: Maxim Davydov Date: Mon, 18 Nov 2019 11:47:01 +0300 Subject: [PATCH 09/14] #3141 Formatted --- core/src/main/scala/cats/Foldable.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index 48529f67a4..21ce2f8669 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -413,7 +413,7 @@ import Foldable.sentinel */ @noop def foldA[G[_], A](fga: F[G[A]])(implicit G: Applicative[G], A: Monoid[A]): G[A] = fold(fga)(Applicative.monoid) - + /** * Fold implemented by mapping `A` values into `B` in a context `G` and then * combining them using the `MonoidK[G]` instance. From 619b1b4f1a4ba66cb5b439029432c59f230e1100 Mon Sep 17 00:00:00 2001 From: Maxim Davydov Date: Mon, 18 Nov 2019 14:46:33 +0300 Subject: [PATCH 10/14] #3141 Refactored --- tests/src/test/scala-2.12/cats/tests/NonEmptyStreamSuite.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/test/scala-2.12/cats/tests/NonEmptyStreamSuite.scala b/tests/src/test/scala-2.12/cats/tests/NonEmptyStreamSuite.scala index 7546ebf21b..4e4e779aba 100644 --- a/tests/src/test/scala-2.12/cats/tests/NonEmptyStreamSuite.scala +++ b/tests/src/test/scala-2.12/cats/tests/NonEmptyStreamSuite.scala @@ -168,5 +168,5 @@ class ReducibleNonEmptyStreamSuite extends ReducibleSuite[NonEmptyStream]("NonEm } def rangeE[L, R](el: Either[L, R], els: Either[L, R]*): NonEmptyStream[Either[L, R]] = - NonEmptyStream(el, Stream(els: _*)) + NonEmptyStream(el, els: _*) } From c910cea28083c18f27ed5e4256214c7315384c3e Mon Sep 17 00:00:00 2001 From: Maxim Davydov Date: Mon, 18 Nov 2019 17:57:11 +0300 Subject: [PATCH 11/14] #3141 Changed .reduceMap signature --- core/src/main/scala/cats/Reducible.scala | 4 ++-- core/src/main/scala/cats/syntax/reducible.scala | 4 ++-- .../src/test/scala/cats/tests/ReducibleSuite.scala | 13 +++++-------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/core/src/main/scala/cats/Reducible.scala b/core/src/main/scala/cats/Reducible.scala index 5872bf78e6..ba498bc633 100644 --- a/core/src/main/scala/cats/Reducible.scala +++ b/core/src/main/scala/cats/Reducible.scala @@ -97,8 +97,8 @@ import simulacrum.{noop, typeclass} * * `noop` usage description [[https://github.com/typelevel/simulacrum/issues/162 here]] */ - @noop def reduceMapA[G[_], A, B](fga: F[G[A]])(f: A => B)(implicit G: Apply[G], B: Semigroup[B]): G[B] = - reduceLeftTo(fga)(ga => G.map(ga)(f))((gb, ga) => G.map2(gb, G.map(ga)(f))(B.combine)) + @noop def reduceMapA[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Apply[G], B: Semigroup[B]): G[B] = + reduceLeftTo(fa)(f)((gb, a) => G.map2(gb, f(a))(B.combine)) /** * Monadic reducing by mapping the `A` values to `G[B]`. combining diff --git a/core/src/main/scala/cats/syntax/reducible.scala b/core/src/main/scala/cats/syntax/reducible.scala index 42cc8dda62..dd8f2b46f4 100644 --- a/core/src/main/scala/cats/syntax/reducible.scala +++ b/core/src/main/scala/cats/syntax/reducible.scala @@ -35,6 +35,6 @@ final class ReducibleOps0[F[_], A](private val fa: F[A]) extends AnyVal { def reduceA[G[_], B](implicit F: Reducible[F], ev: A <:< G[B], G: Apply[G], B: Semigroup[B]): G[B] = F.reduceA[G, B](fa.asInstanceOf[F[G[B]]]) - def reduceMapA[G[_], B, C](f: B => C)(implicit F: Reducible[F], ev: A <:< G[B], G: Apply[G], C: Semigroup[C]): G[C] = - F.reduceMapA[G, B, C](fa.asInstanceOf[F[G[B]]])(f) + def reduceMapA[G[_], B](f: A => G[B])(implicit F: Reducible[F], G: Apply[G], C: Semigroup[B]): G[B] = + F.reduceMapA[G, A, B](fa)(f) } diff --git a/tests/src/test/scala/cats/tests/ReducibleSuite.scala b/tests/src/test/scala/cats/tests/ReducibleSuite.scala index f22e05334c..db786be42a 100644 --- a/tests/src/test/scala/cats/tests/ReducibleSuite.scala +++ b/tests/src/test/scala/cats/tests/ReducibleSuite.scala @@ -102,21 +102,18 @@ abstract class ReducibleSuite[F[_]: Reducible](name: String)(implicit ArbFInt: A } test(s"Reducible[$name].reduceMapA successful case") { - def intToString(i: Int): String = i.toString - val expected = "123" - val actual = - rangeE(1.asRight[String], 2.asRight[String], 3.asRight[String]).reduceMapA(intToString) + val actual = range(1, 3).reduceMapA(_.toString.some) - actual should ===(expected.asRight[String]) + actual should ===(expected.some) } test(s"Reducible[$name].reduceMapA failure case") { - def intToString(i: Int): String = i.toString + def intToString(i: Long): Either[String, Int] = if (i == 2) i.toInt.asRight else "boom!!!".asLeft val expected = "boom!!!" - val actual = rangeE(1.asRight, "boom!!!".asLeft, 3.asRight).reduceMapA(intToString) - actual should ===(expected.asLeft[String]) + val actual = range(1, 3).reduceMapA(intToString) + actual should ===(expected.asLeft[Int]) } test(s"Reducible[$name].toNonEmptyList/toList consistency") { From 82c16e1408fd84b18ce01c4c52db2b19d817201f Mon Sep 17 00:00:00 2001 From: Maxim Davydov Date: Tue, 19 Nov 2019 11:41:16 +0300 Subject: [PATCH 12/14] #3141 Removed noop on .reduceMapA --- core/src/main/scala/cats/Reducible.scala | 4 ++-- core/src/main/scala/cats/syntax/reducible.scala | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/cats/Reducible.scala b/core/src/main/scala/cats/Reducible.scala index ba498bc633..bcfb81657f 100644 --- a/core/src/main/scala/cats/Reducible.scala +++ b/core/src/main/scala/cats/Reducible.scala @@ -92,12 +92,12 @@ import simulacrum.{noop, typeclass} reduce(fga)(Apply.semigroup) /** - * Apply `f` to each applicative `ga` of `fga` and combine them using the + * Apply `f` to each `a` of `fa` and combine the result into Apply[G] using the * given `Semigroup[B]`. * * `noop` usage description [[https://github.com/typelevel/simulacrum/issues/162 here]] */ - @noop def reduceMapA[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Apply[G], B: Semigroup[B]): G[B] = + def reduceMapA[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Apply[G], B: Semigroup[B]): G[B] = reduceLeftTo(fa)(f)((gb, a) => G.map2(gb, f(a))(B.combine)) /** diff --git a/core/src/main/scala/cats/syntax/reducible.scala b/core/src/main/scala/cats/syntax/reducible.scala index dd8f2b46f4..4088d7c007 100644 --- a/core/src/main/scala/cats/syntax/reducible.scala +++ b/core/src/main/scala/cats/syntax/reducible.scala @@ -34,7 +34,4 @@ final class ReducibleOps0[F[_], A](private val fa: F[A]) extends AnyVal { def reduceA[G[_], B](implicit F: Reducible[F], ev: A <:< G[B], G: Apply[G], B: Semigroup[B]): G[B] = F.reduceA[G, B](fa.asInstanceOf[F[G[B]]]) - - def reduceMapA[G[_], B](f: A => G[B])(implicit F: Reducible[F], G: Apply[G], C: Semigroup[B]): G[B] = - F.reduceMapA[G, A, B](fa)(f) } From 6eebfebb77c4f5f3220bf7d5724e6a847340b29a Mon Sep 17 00:00:00 2001 From: Maxim Davydov Date: Tue, 19 Nov 2019 11:41:55 +0300 Subject: [PATCH 13/14] #3141 Fixed docs --- core/src/main/scala/cats/Reducible.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/src/main/scala/cats/Reducible.scala b/core/src/main/scala/cats/Reducible.scala index bcfb81657f..b04f581c99 100644 --- a/core/src/main/scala/cats/Reducible.scala +++ b/core/src/main/scala/cats/Reducible.scala @@ -94,8 +94,6 @@ import simulacrum.{noop, typeclass} /** * Apply `f` to each `a` of `fa` and combine the result into Apply[G] using the * given `Semigroup[B]`. - * - * `noop` usage description [[https://github.com/typelevel/simulacrum/issues/162 here]] */ def reduceMapA[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Apply[G], B: Semigroup[B]): G[B] = reduceLeftTo(fa)(f)((gb, a) => G.map2(gb, f(a))(B.combine)) From c63b8bc7b467fc986e389bd6e7909b0ed7d9c21b Mon Sep 17 00:00:00 2001 From: Maxim Davydov Date: Wed, 20 Nov 2019 18:21:41 +0300 Subject: [PATCH 14/14] #3141 Removed changes from reduceMapK --- core/src/main/scala/cats/syntax/reducible.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/syntax/reducible.scala b/core/src/main/scala/cats/syntax/reducible.scala index 4088d7c007..0b542c8742 100644 --- a/core/src/main/scala/cats/syntax/reducible.scala +++ b/core/src/main/scala/cats/syntax/reducible.scala @@ -29,8 +29,7 @@ final class ReducibleOps0[F[_], A](private val fa: F[A]) extends AnyVal { * a: String = "foo321" * }}} * */ - def reduceMapK[G[_], B](f: A => G[B])(implicit F: Reducible[F], G: SemigroupK[G]): G[B] = - F.reduceLeftTo(fa)(f)((b, a) => G.combineK(b, f(a))) + def reduceMapK[G[_], B](f: A => G[B])(implicit F: Reducible[F], G: SemigroupK[G]): G[B] = F.reduceMapK[G, A, B](fa)(f) def reduceA[G[_], B](implicit F: Reducible[F], ev: A <:< G[B], G: Apply[G], B: Semigroup[B]): G[B] = F.reduceA[G, B](fa.asInstanceOf[F[G[B]]])