Skip to content

Commit

Permalink
Add filterFold and collectFold to Foldable (#2452)
Browse files Browse the repository at this point in the history
* add filterFold and collectFold to Foldable

* add syntax for collectFold

* remove unwanted test file

* add properties for collectFold and filterFold using toList

* fix filterFold

* move filterFold and collectFold to syntax for binary compatibility

* use a more consistent implicit style

* rename filterFold to collectSomeFold
  • Loading branch information
kun-song authored and Luka Jacobowitz committed Sep 12, 2018
1 parent c138c01 commit 30c29e8
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 0 deletions.
29 changes: 29 additions & 0 deletions core/src/main/scala/cats/syntax/foldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,33 @@ final class FoldableOps[F[_], A](val fa: F[A]) extends AnyVal {
case Some((a, src)) => G.map(p(a))(if (_) Right(Some(a)) else Left(src.value))
case None => G.pure(Right(None))
})

/**
* Tear down a subset of this structure using a `PartialFunction`.
*{{{
* scala> import cats.implicits._
* scala> val xs = List(1, 2, 3, 4)
* scala> xs.collectFold { case n if n % 2 == 0 => n }
* res0: Int = 6
*}}}
*/
def collectFold[M](f: PartialFunction[A, M])(implicit F: Foldable[F], M: Monoid[M]): M =
F.foldLeft(fa, M.empty)((acc, a) M.combine(acc, f.applyOrElse(a, (_: A) M.empty)))

/**
* Tear down a subset of this structure using a `A => Option[M]`.
*{{{
* scala> import cats.implicits._
* scala> val xs = List(1, 2, 3, 4)
* scala> def f(n: Int): Option[Int] = if (n % 2 == 0) Some(n) else None
* scala> xs.collectSomeFold(f)
* res0: Int = 6
*}}}
*/
def collectSomeFold[M](f: A Option[M])(implicit F: Foldable[F], M: Monoid[M]): M =
F.foldLeft(fa, M.empty)((acc, a) f(a) match {
case Some(x) M.combine(acc, x)
case None acc
})

}
14 changes: 14 additions & 0 deletions tests/src/test/scala/cats/tests/FoldableSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,20 @@ abstract class FoldableSuite[F[_]: Foldable](name: String)(
}
}

test(s"Foldable[$name] partial summation") {
forAll { (fa: F[String], f: String Boolean)
val m: Monoid[String] = Monoid[String]

val pf: PartialFunction[String, String] = {
case n if f(n) n
}
fa.collectFold(pf) should === (fa.toList.collect(pf).fold(m.empty)(m.combine))

def g(a: String): Option[String] = Some(a).filter(f)
fa.collectSomeFold(g) should === (fa.toList.filter(f).fold(m.empty)(m.combine))
}
}

test(s"Foldable[$name].find/exists/forall/findM/existsM/forallM/filter_/dropWhile_") {
forAll { (fa: F[Int], n: Int) =>
fa.find(_ > n) should === (iterator(fa).find(_ > n))
Expand Down

0 comments on commit 30c29e8

Please sign in to comment.