Skip to content

Commit

Permalink
add foldMapA to Foldable and add a test for sufficient short-circuiti…
Browse files Browse the repository at this point in the history
…ng (#3130)
  • Loading branch information
mberndt123 authored and LukaJCB committed Nov 9, 2019
1 parent 7fb1327 commit fc6580b
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 0 deletions.
8 changes: 8 additions & 0 deletions core/src/main/scala/cats/Foldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,14 @@ import Foldable.sentinel
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, _)))

/**
* Equivalent to foldMapM.
* The difference is that foldMapA only requires G to be an Applicative
* rather than a Monad. It is also slower due to use of Eval.
*/
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

/**
* Traverse `F[A]` using `Applicative[G]`.
*
Expand Down
12 changes: 12 additions & 0 deletions tests/src/test/scala/cats/tests/FoldableSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,18 @@ class FoldableSuiteAdditional extends CatsSuite with ScalaVersionSpecificFoldabl
(Some(x): Option[String])
}
assert(sumMapM == Some("AaronBettyCalvinDeirdra"))

// foldMapM should short-circuit and not call the function when not necessary
val f = (_: String) match {
case "Calvin" => None
case "Deirdra" =>
fail: Unit // : Unit ascription suppresses unreachable code warning
None
case x => Some(x)
}
names.foldMapM(f)
names.foldMapA(f)

val isNotCalvin: String => Option[String] =
x => if (x == "Calvin") None else Some(x)
val notCalvin = F.foldM(names, "") { (acc, x) =>
Expand Down

0 comments on commit fc6580b

Please sign in to comment.