diff --git a/core/src/main/scala/cats/syntax/all.scala b/core/src/main/scala/cats/syntax/all.scala index 495f734b9b..5a65ddeaf5 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -79,4 +79,8 @@ trait AllSyntaxBinCompat2 trait AllSyntaxBinCompat3 extends UnorderedFoldableSyntax with Function1Syntax -trait AllSyntaxBinCompat4 extends TraverseFilterSyntaxBinCompat0 with ParallelApplySyntax +trait AllSyntaxBinCompat4 + extends TraverseFilterSyntaxBinCompat0 + with ParallelApplySyntax + with FoldableSyntaxBinCompat0 + with ReducibleSyntaxBinCompat0 diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 2df8423847..93e130d142 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -9,6 +9,11 @@ trait FoldableSyntax extends Foldable.ToFoldableOps with UnorderedFoldable.ToUno new FoldableOps[F, A](fa) } +trait FoldableSyntaxBinCompat0 { + implicit final def catsSyntaxFoldableOps0[F[_], A](fa: F[A]): FoldableOps0[F, A] = + new FoldableOps0[F, A](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) @@ -192,3 +197,21 @@ final class FoldableOps[F[_], A](private val fa: F[A]) extends AnyVal { ) } + +final class FoldableOps0[F[_], A](val fa: F[A]) extends AnyVal { + + /** + * Fold implemented by mapping `A` values into `B` in a context `G` and then + * combining them using the `MonoidK[G]` instance. + * + * {{{ + * scala> import cats._, cats.implicits._ + * scala> val f: Int => Endo[String] = i => (s => s + i) + * scala> val x: Endo[String] = List(1, 2, 3).foldMapK(f) + * scala> val a = x("foo") + * a: String = "foo321" + * }}} + * */ + def foldMapK[G[_], B](f: A => G[B])(implicit F: Foldable[F], G: MonoidK[G]): G[B] = + F.foldMap(fa)(f)(G.algebra) +} diff --git a/core/src/main/scala/cats/syntax/package.scala b/core/src/main/scala/cats/syntax/package.scala index 19bb9cf40e..a4f02e5596 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 + object foldable extends FoldableSyntax with FoldableSyntaxBinCompat0 object functor extends FunctorSyntax object functorFilter extends FunctorFilterSyntax object group extends GroupSyntax @@ -42,7 +42,7 @@ package object syntax { object parallel extends ParallelSyntax with ParallelTraverseSyntax with ParallelFlatSyntax with ParallelApplySyntax object partialOrder extends PartialOrderSyntax object profunctor extends ProfunctorSyntax - object reducible extends ReducibleSyntax + object reducible extends ReducibleSyntax with ReducibleSyntaxBinCompat0 object representable extends RepresentableSyntax object semigroup extends SemigroupSyntax object semigroupal extends SemigroupalSyntax diff --git a/core/src/main/scala/cats/syntax/reducible.scala b/core/src/main/scala/cats/syntax/reducible.scala index 8e2e67ef43..2fe183ad64 100644 --- a/core/src/main/scala/cats/syntax/reducible.scala +++ b/core/src/main/scala/cats/syntax/reducible.scala @@ -9,3 +9,26 @@ trait ReducibleSyntax extends Reducible.ToReducibleOps { final class NestedReducibleOps[F[_], G[_], A](private val fga: F[G[A]]) extends AnyVal { def reduceK(implicit F: Reducible[F], G: SemigroupK[G]): G[A] = F.reduceK(fga) } + +trait ReducibleSyntaxBinCompat0 { + implicit final def catsSyntaxReducibleOps0[F[_], A](fa: F[A]): ReducibleOps0[F, A] = + new ReducibleOps0[F, A](fa) +} + +final class ReducibleOps0[F[_], A](val fa: F[A]) extends AnyVal { + + /** + * Apply `f` to each element of `fa` and combine them using the + * given `SemigroupK[G]`. + * + * {{{ + * scala> import cats._, cats.data._, cats.implicits._ + * scala> val f: Int => Endo[String] = i => (s => s + i) + * scala> val x: Endo[String] = NonEmptyList.of(1, 2, 3).reduceMapK(f) + * scala> val a = x("foo") + * 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))) +}