From b51cc0fc1933bf15e53f72ad140b612dc349a4a7 Mon Sep 17 00:00:00 2001 From: Kailuo Wang Date: Wed, 6 Dec 2017 17:12:40 -0500 Subject: [PATCH 1/4] added reduceRightK and Endo --- core/src/main/scala/cats/Foldable.scala | 18 ++++++++++++++++++ core/src/main/scala/cats/package.scala | 1 + .../test/scala/cats/tests/CategorySuite.scala | 1 - .../test/scala/cats/tests/ComposeSuite.scala | 1 - .../test/scala/cats/tests/FoldableSuite.scala | 11 ++++++++++- .../test/scala/cats/tests/ReducibleSuite.scala | 3 +-- 6 files changed, 30 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index 2d5f931832..029ed6e856 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -244,6 +244,24 @@ import Foldable.sentinel A.combine(acc, a) } + /** + * Like `foldK` but from the right side. + * One use case would be endo functions (`A => A`) chaining + * because the default MonoidK instance for endo functions + * is using `compose` rather than the `andThen` + * {{{ + * scala> import cats.implicits._, cats.Endo + * scala> val l: List[Endo[Int]] = List(_ * 2, _ + 3) + * scala> val f = l.reduceRightK //using `compose` to chain the functions + * scala> f(1) + * res0: Int = 5 + * }}} + */ + def reduceRightK[G[_], A](fga: F[G[A]])(implicit G: MonoidK[G]): G[A] = + foldRight(fga, Eval.now(G.empty[A])) { (ga, ega) => + ega.map(rga => G.combineK(rga, ga)) + }.value + /** * Alias for [[fold]]. */ diff --git a/core/src/main/scala/cats/package.scala b/core/src/main/scala/cats/package.scala index 46a24e9837..cab9ea844f 100644 --- a/core/src/main/scala/cats/package.scala +++ b/core/src/main/scala/cats/package.scala @@ -32,6 +32,7 @@ package object cats { * encodes pure unary function application. */ type Id[A] = A + type Endo[A] = A => A implicit val catsInstancesForId: Bimonad[Id] with CommutativeMonad[Id] with Comonad[Id] with NonEmptyTraverse[Id] = new Bimonad[Id] with CommutativeMonad[Id] with Comonad[Id] with NonEmptyTraverse[Id] { def pure[A](a: A): A = a diff --git a/tests/src/test/scala/cats/tests/CategorySuite.scala b/tests/src/test/scala/cats/tests/CategorySuite.scala index d4e215d997..5eb98a484b 100644 --- a/tests/src/test/scala/cats/tests/CategorySuite.scala +++ b/tests/src/test/scala/cats/tests/CategorySuite.scala @@ -9,7 +9,6 @@ import cats.laws.discipline.eq.catsLawsEqForFn1 class CategorySuite extends CatsSuite { val functionCategory = Category[Function1] - type Endo[A] = Function1[A, A] checkAll("Category[Function1].algebraK", MonoidKTests[Endo](functionCategory.algebraK).monoidK[Int]) checkAll("Category[Function1].algebraK", SerializableTests.serializable(functionCategory.algebraK)) diff --git a/tests/src/test/scala/cats/tests/ComposeSuite.scala b/tests/src/test/scala/cats/tests/ComposeSuite.scala index 10f839f893..1c6ca48343 100644 --- a/tests/src/test/scala/cats/tests/ComposeSuite.scala +++ b/tests/src/test/scala/cats/tests/ComposeSuite.scala @@ -8,7 +8,6 @@ import cats.laws.discipline.eq.catsLawsEqForFn1 class ComposeSuite extends CatsSuite { val functionCompose = Compose[Function1] - type Endo[A] = Function1[A, A] checkAll("Compose[Function1].algebraK", SemigroupKTests[Endo](functionCompose.algebraK).semigroupK[Int]) checkAll("Compose[Function1].algebraK", SerializableTests.serializable(functionCompose.algebraK)) diff --git a/tests/src/test/scala/cats/tests/FoldableSuite.scala b/tests/src/test/scala/cats/tests/FoldableSuite.scala index 487e8f32f2..e0a3a99016 100644 --- a/tests/src/test/scala/cats/tests/FoldableSuite.scala +++ b/tests/src/test/scala/cats/tests/FoldableSuite.scala @@ -9,7 +9,10 @@ import cats.instances.all._ import cats.data._ import cats.laws.discipline.arbitrary._ -abstract class FoldableSuite[F[_]: Foldable](name: String)(implicit ArbFInt: Arbitrary[F[Int]], ArbFString: Arbitrary[F[String]]) extends CatsSuite with PropertyChecks { +abstract class FoldableSuite[F[_]: Foldable](name: String)( + implicit ArbFInt: Arbitrary[F[Int]], + ArbFString: Arbitrary[F[String]], + ArbFListString: Arbitrary[F[List[String]]]) extends CatsSuite with PropertyChecks { def iterator[T](fa: F[T]): Iterator[T] @@ -33,6 +36,12 @@ abstract class FoldableSuite[F[_]: Foldable](name: String)(implicit ArbFInt: Arb } } + test("Foldable#reduceRightK") { + forAll { (fi: F[List[String]]) => + fi.reduceRightK should === (fi.foldRight(Eval.now(List.empty[String]))((l, el) => el.map(_ ++ l)).value) + } + } + test("Foldable#partitionEither consistent with List#partition") { forAll { (fi: F[Int], f: Int => Either[String, String]) => val list = Foldable[F].toList(fi) diff --git a/tests/src/test/scala/cats/tests/ReducibleSuite.scala b/tests/src/test/scala/cats/tests/ReducibleSuite.scala index a92fdd25b5..e8f872d7ac 100644 --- a/tests/src/test/scala/cats/tests/ReducibleSuite.scala +++ b/tests/src/test/scala/cats/tests/ReducibleSuite.scala @@ -2,7 +2,6 @@ package cats package tests import org.scalacheck.Arbitrary - import cats.data.NonEmptyList class ReducibleSuiteAdditional extends CatsSuite { @@ -71,7 +70,7 @@ class ReducibleSuiteAdditional extends CatsSuite { } -abstract class ReducibleSuite[F[_]: Reducible](name: String)(implicit ArbFInt: Arbitrary[F[Int]], ArbFString: Arbitrary[F[String]]) extends FoldableSuite[F](name) { +abstract class ReducibleSuite[F[_]: Reducible](name: String)(implicit ArbFInt: Arbitrary[F[Int]], ArbFString: Arbitrary[F[String]], ArbFListString: Arbitrary[F[List[String]]]) extends FoldableSuite[F](name) { def range(start: Long, endInclusive: Long): F[Long] test(s"Reducible[$name].reduceLeftM stack safety") { From 9410809094d82bdabfa08cb1c3b9564b567c98c7 Mon Sep 17 00:00:00 2001 From: Kailuo Wang Date: Wed, 6 Dec 2017 17:15:32 -0500 Subject: [PATCH 2/4] added mima excpetion --- build.sbt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index c0768dc1f5..233330e73b 100644 --- a/build.sbt +++ b/build.sbt @@ -320,7 +320,9 @@ def mimaSettings(moduleName: String) = Seq( exclude[ReversedMissingMethodProblem]("cats.MonadError.rethrow"), exclude[ReversedMissingMethodProblem]("cats.syntax.MonadErrorSyntax.catsSyntaxMonadErrorRethrow"), exclude[DirectMissingMethodProblem]("cats.data.CokleisliArrow.id"), - exclude[IncompatibleResultTypeProblem]("cats.data.CokleisliArrow.id") + exclude[IncompatibleResultTypeProblem]("cats.data.CokleisliArrow.id"), + exclude[ReversedMissingMethodProblem]("cats.Foldable.reduceRightK"), + exclude[ReversedMissingMethodProblem]("cats.Foldable#Ops.reduceRightK") ) } ) From 7796307e14ab3d043b7b0a4c515e9a34f17e5f92 Mon Sep 17 00:00:00 2001 From: Kailuo Wang Date: Thu, 7 Dec 2017 11:49:05 -0500 Subject: [PATCH 3/4] removed reduceRightK --- build.sbt | 4 +--- core/src/main/scala/cats/Foldable.scala | 18 ------------------ .../test/scala/cats/tests/FoldableSuite.scala | 9 +-------- .../test/scala/cats/tests/ReducibleSuite.scala | 5 ++++- 4 files changed, 6 insertions(+), 30 deletions(-) diff --git a/build.sbt b/build.sbt index 233330e73b..c0768dc1f5 100644 --- a/build.sbt +++ b/build.sbt @@ -320,9 +320,7 @@ def mimaSettings(moduleName: String) = Seq( exclude[ReversedMissingMethodProblem]("cats.MonadError.rethrow"), exclude[ReversedMissingMethodProblem]("cats.syntax.MonadErrorSyntax.catsSyntaxMonadErrorRethrow"), exclude[DirectMissingMethodProblem]("cats.data.CokleisliArrow.id"), - exclude[IncompatibleResultTypeProblem]("cats.data.CokleisliArrow.id"), - exclude[ReversedMissingMethodProblem]("cats.Foldable.reduceRightK"), - exclude[ReversedMissingMethodProblem]("cats.Foldable#Ops.reduceRightK") + exclude[IncompatibleResultTypeProblem]("cats.data.CokleisliArrow.id") ) } ) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index 029ed6e856..2d5f931832 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -244,24 +244,6 @@ import Foldable.sentinel A.combine(acc, a) } - /** - * Like `foldK` but from the right side. - * One use case would be endo functions (`A => A`) chaining - * because the default MonoidK instance for endo functions - * is using `compose` rather than the `andThen` - * {{{ - * scala> import cats.implicits._, cats.Endo - * scala> val l: List[Endo[Int]] = List(_ * 2, _ + 3) - * scala> val f = l.reduceRightK //using `compose` to chain the functions - * scala> f(1) - * res0: Int = 5 - * }}} - */ - def reduceRightK[G[_], A](fga: F[G[A]])(implicit G: MonoidK[G]): G[A] = - foldRight(fga, Eval.now(G.empty[A])) { (ga, ega) => - ega.map(rga => G.combineK(rga, ga)) - }.value - /** * Alias for [[fold]]. */ diff --git a/tests/src/test/scala/cats/tests/FoldableSuite.scala b/tests/src/test/scala/cats/tests/FoldableSuite.scala index e0a3a99016..7928469ad0 100644 --- a/tests/src/test/scala/cats/tests/FoldableSuite.scala +++ b/tests/src/test/scala/cats/tests/FoldableSuite.scala @@ -11,8 +11,7 @@ import cats.laws.discipline.arbitrary._ abstract class FoldableSuite[F[_]: Foldable](name: String)( implicit ArbFInt: Arbitrary[F[Int]], - ArbFString: Arbitrary[F[String]], - ArbFListString: Arbitrary[F[List[String]]]) extends CatsSuite with PropertyChecks { + ArbFString: Arbitrary[F[String]]) extends CatsSuite with PropertyChecks { def iterator[T](fa: F[T]): Iterator[T] @@ -36,12 +35,6 @@ abstract class FoldableSuite[F[_]: Foldable](name: String)( } } - test("Foldable#reduceRightK") { - forAll { (fi: F[List[String]]) => - fi.reduceRightK should === (fi.foldRight(Eval.now(List.empty[String]))((l, el) => el.map(_ ++ l)).value) - } - } - test("Foldable#partitionEither consistent with List#partition") { forAll { (fi: F[Int], f: Int => Either[String, String]) => val list = Foldable[F].toList(fi) diff --git a/tests/src/test/scala/cats/tests/ReducibleSuite.scala b/tests/src/test/scala/cats/tests/ReducibleSuite.scala index e8f872d7ac..b7d3afe4f5 100644 --- a/tests/src/test/scala/cats/tests/ReducibleSuite.scala +++ b/tests/src/test/scala/cats/tests/ReducibleSuite.scala @@ -70,7 +70,10 @@ class ReducibleSuiteAdditional extends CatsSuite { } -abstract class ReducibleSuite[F[_]: Reducible](name: String)(implicit ArbFInt: Arbitrary[F[Int]], ArbFString: Arbitrary[F[String]], ArbFListString: Arbitrary[F[List[String]]]) extends FoldableSuite[F](name) { +abstract class ReducibleSuite[F[_]: Reducible](name: String)( + implicit ArbFInt: Arbitrary[F[Int]], + ArbFString: Arbitrary[F[String]]) extends FoldableSuite[F](name) { + def range(start: Long, endInclusive: Long): F[Long] test(s"Reducible[$name].reduceLeftM stack safety") { From 828be44c70bfc3d656c6bf062a9ff11027eb15eb Mon Sep 17 00:00:00 2001 From: Kailuo Wang Date: Thu, 7 Dec 2017 16:35:37 -0500 Subject: [PATCH 4/4] minor --- core/src/main/scala/cats/instances/function.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/instances/function.scala b/core/src/main/scala/cats/instances/function.scala index f6841aab70..19bbd678e9 100644 --- a/core/src/main/scala/cats/instances/function.scala +++ b/core/src/main/scala/cats/instances/function.scala @@ -88,7 +88,7 @@ private[instances] sealed trait Function1Instances extends Function1Instances0 { def compose[A, B, C](f: B => C, g: A => B): A => C = f.compose(g) } - implicit val catsStdMonoidKForFunction1: MonoidK[λ[α => Function1[α, α]]] = + implicit val catsStdMonoidKForFunction1: MonoidK[Endo] = Category[Function1].algebraK }