From 046f8d1f4f52951f66a3f277f05deb9d008f649a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Miguel=20Mej=C3=ADa=20Su=C3=A1rez?= Date: Fri, 21 Apr 2023 11:31:53 -0500 Subject: [PATCH 1/2] Add foldTraverse & friends --- core/src/main/scala/cats/Traverse.scala | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/cats/Traverse.scala b/core/src/main/scala/cats/Traverse.scala index f0f0ac0a17..e64aa19872 100644 --- a/core/src/main/scala/cats/Traverse.scala +++ b/core/src/main/scala/cats/Traverse.scala @@ -187,9 +187,9 @@ trait Traverse[F[_]] extends Functor[F] with Foldable[F] with UnorderedTraverse[ mapWithLongIndex(fa)((a, long) => (a, long)) /** - * If `fa` contains the element at index `idx`, - * return the copy of `fa` where the element at `idx` is replaced with `b`. - * If there is no element with such an index, return `None`. + * If `fa` contains the element at index `idx`, + * return the copy of `fa` where the element at `idx` is replaced with `b`. + * If there is no element with such an index, return `None`. * * The behavior is consistent with the Scala collection library's * `updated` for collections such as `List`. @@ -213,6 +213,22 @@ trait Traverse[F[_]] extends Functor[F] with Foldable[F] with UnorderedTraverse[ override def unorderedSequence[G[_]: CommutativeApplicative, A](fga: F[G[A]]): G[F[A]] = sequence(fga) + + def foldTraverse[A, B, G[_]](fa: F[A])(f: A => G[B])(implicit G: Monad[G], M: Monoid[B]): G[B] = + foldM(fa, M.empty) { case (acc, a) => + G.map(f(a)) { b => + M.combine(acc, b) + } + } + + def foldTraverseK[A, B, G[_], H[_]](fa: F[A])(f: A => G[H[B]])(implicit G: Monad[G], M: MonoidK[H]): G[H[B]] = + foldTraverse(fa)(f)(G, M.algebra) + + def foldSequence[A, G[_]](fga: F[G[A]])(implicit G: Monad[G], M: Monoid[A]): G[A] = + foldTraverse(fga)(identity) + + def foldSequenceK[A, G[_], H[_]](fgha: F[G[H[A]]])(implicit G: Monad[G], M: MonoidK[H]): G[H[A]] = + foldTraverseK(fgha)(identity) } object Traverse { From 25fc19e6f38f3c3000a42c78be7573a266416364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Miguel=20Mej=C3=ADa=20Su=C3=A1rez?= Date: Fri, 21 Apr 2023 12:07:40 -0500 Subject: [PATCH 2/2] Move foldTraverse & friends to Foldable --- core/src/main/scala/cats/Foldable.scala | 12 ++++++++++++ core/src/main/scala/cats/Traverse.scala | 16 ---------------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index d5cddc154d..9dcb217c41 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -483,6 +483,9 @@ trait Foldable[F[_]] extends UnorderedFoldable[F] with FoldableNFunctions[F] { s } } + def foldMK[A, G[_], H[_]](fgha: F[G[H[A]]])(implicit G: Monad[G], M: MonoidK[H]): G[H[A]] = + foldMapMK(fgha)(identity) + /** * Fold implemented using the given `Applicative[G]` and `Monoid[A]` instance. * @@ -500,6 +503,9 @@ trait Foldable[F[_]] extends UnorderedFoldable[F] with FoldableNFunctions[F] { s def foldA[G[_], A](fga: F[G[A]])(implicit G: Applicative[G], A: Monoid[A]): G[A] = foldMapA(fga)(identity) + def foldAK[A, G[_], H[_]](fgha: F[G[H[A]]])(implicit G: Applicative[G], M: MonoidK[H]): G[H[A]] = + foldMapAK(fgha)(identity) + /** * Fold implemented by mapping `A` values into `B` in a context `G` and then * combining them using the `MonoidK[G]` instance. @@ -545,6 +551,9 @@ trait Foldable[F[_]] extends UnorderedFoldable[F] with FoldableNFunctions[F] { s def foldMapM[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Monad[G], B: Monoid[B]): G[B] = foldM(fa, B.empty)((b, a) => G.map(f(a))(B.combine(b, _))) + def foldMapMK[A, B, G[_], H[_]](fa: F[A])(f: A => G[H[B]])(implicit G: Monad[G], M: MonoidK[H]): G[H[B]] = + foldMapM(fa)(f)(G, M.algebra) + /** * Fold in an [[Applicative]] context by mapping the `A` values to `G[B]`. combining * the `B` values using the given `Monoid[B]` instance. @@ -566,6 +575,9 @@ trait Foldable[F[_]] extends UnorderedFoldable[F] with FoldableNFunctions[F] { s def foldMapA[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Applicative[G], B: Monoid[B]): G[B] = foldRight(fa, Eval.now(G.pure(B.empty)))((a, egb) => G.map2Eval(f(a), egb)(B.combine)).value + def foldMapAK[A, B, G[_], H[_]](fa: F[A])(f: A => G[H[B]])(implicit G: Applicative[G], M: MonoidK[H]): G[H[B]] = + foldMapA(fa)(f)(G, M.algebra) + /** * Traverse `F[A]` using `Applicative[G]`. * diff --git a/core/src/main/scala/cats/Traverse.scala b/core/src/main/scala/cats/Traverse.scala index e64aa19872..254d7f8fef 100644 --- a/core/src/main/scala/cats/Traverse.scala +++ b/core/src/main/scala/cats/Traverse.scala @@ -213,22 +213,6 @@ trait Traverse[F[_]] extends Functor[F] with Foldable[F] with UnorderedTraverse[ override def unorderedSequence[G[_]: CommutativeApplicative, A](fga: F[G[A]]): G[F[A]] = sequence(fga) - - def foldTraverse[A, B, G[_]](fa: F[A])(f: A => G[B])(implicit G: Monad[G], M: Monoid[B]): G[B] = - foldM(fa, M.empty) { case (acc, a) => - G.map(f(a)) { b => - M.combine(acc, b) - } - } - - def foldTraverseK[A, B, G[_], H[_]](fa: F[A])(f: A => G[H[B]])(implicit G: Monad[G], M: MonoidK[H]): G[H[B]] = - foldTraverse(fa)(f)(G, M.algebra) - - def foldSequence[A, G[_]](fga: F[G[A]])(implicit G: Monad[G], M: Monoid[A]): G[A] = - foldTraverse(fga)(identity) - - def foldSequenceK[A, G[_], H[_]](fgha: F[G[H[A]]])(implicit G: Monad[G], M: MonoidK[H]): G[H[A]] = - foldTraverseK(fgha)(identity) } object Traverse {