Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 3141 #3150

Merged
merged 15 commits into from
Dec 10, 2019
20 changes: 20 additions & 0 deletions core/src/main/scala/cats/Foldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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] =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the name here, and I don't think we want to set a precedent for adding methods that just replace a A: Monoid argument with a G[A] + G: Applicative[G], A: Monoid argument, or at least not without a clear case that doing so makes some common usage much more convenient.

foldLeft(fga, G.pure(A.empty)) { (acc, ga) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to prefer this implementation over fold(fga)(G.monoid)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is better, I didn't know about this function.

G.map2(acc, ga)(A.combine)
}

/**
* Alias for [[foldM]].
*/
Expand Down
16 changes: 16 additions & 0 deletions core/src/main/scala/cats/Reducible.scala
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,22 @@ 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`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about "generalization" here—in what sense is the reduce signature less general?

Also, couldn't the constraint both here and below be Apply instead of Applicative?

*/
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))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not reduce(fga)(Apply[G].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] =
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.
Expand Down