Skip to content

Commit

Permalink
Merge pull request #2380 from barambani/issue-2363
Browse files Browse the repository at this point in the history
Add combineAllOption to Foldable
  • Loading branch information
travisbrown authored Nov 14, 2019
2 parents 038d683 + 2d835f1 commit 8d67ec6
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 3 deletions.
11 changes: 11 additions & 0 deletions core/src/main/scala-2.12/cats/compat/FoldableCompat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package cats
package compat

private[cats] object FoldableCompat {

def toIterable[F[_], A](fa: F[A])(F: Foldable[F]): Iterable[A] =
F.foldRight[A, Stream[A]](fa, Eval.now(Stream.empty)) { (a, eb) =>
eb.map(Stream.cons(a, _))
}
.value
}
2 changes: 2 additions & 0 deletions core/src/main/scala-2.12/cats/instances/stream.scala
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ trait StreamInstances extends cats.kernel.instances.StreamInstances {

override def toList[A](fa: Stream[A]): List[A] = fa.toList

override def toIterable[A](fa: Stream[A]): Iterable[A] = fa

override def reduceLeftOption[A](fa: Stream[A])(f: (A, A) => A): Option[A] =
fa.reduceLeftOption(f)

Expand Down
11 changes: 11 additions & 0 deletions core/src/main/scala-2.13+/cats/compat/FoldableCompat.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package cats
package compat

private[cats] object FoldableCompat {

def toIterable[F[_], A](fa: F[A])(F: Foldable[F]): Iterable[A] =
F.foldRight[A, LazyList[A]](fa, Eval.now(LazyList.empty)) { (a, eb) =>
eb.map(LazyList.cons(a, _))
}
.value
}
2 changes: 2 additions & 0 deletions core/src/main/scala-2.13+/cats/instances/lazyList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ trait LazyListInstances extends cats.kernel.instances.LazyListInstances {

override def toList[A](fa: LazyList[A]): List[A] = fa.toList

override def toIterable[A](fa: LazyList[A]): Iterable[A] = fa

override def reduceLeftOption[A](fa: LazyList[A])(f: (A, A) => A): Option[A] =
fa.reduceLeftOption(f)

Expand Down
2 changes: 2 additions & 0 deletions core/src/main/scala-2.13+/cats/instances/stream.scala
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ trait StreamInstances extends cats.kernel.instances.StreamInstances {

override def toList[A](fa: Stream[A]): List[A] = fa.toList

override def toIterable[A](fa: Stream[A]): Iterable[A] = fa

override def reduceLeftOption[A](fa: Stream[A])(f: (A, A) => A): Option[A] =
fa.reduceLeftOption(f)

Expand Down
16 changes: 13 additions & 3 deletions core/src/main/scala/cats/Foldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -273,15 +273,25 @@ import Foldable.sentinel
* Fold implemented using the given Monoid[A] instance.
*/
def fold[A](fa: F[A])(implicit A: Monoid[A]): A =
foldLeft(fa, A.empty) { (acc, a) =>
A.combine(acc, a)
}
A.combineAll(toIterable(fa))

/**
* Alias for [[fold]].
*/
def combineAll[A: Monoid](fa: F[A]): A = fold(fa)

def combineAllOption[A](fa: F[A])(implicit ev: Semigroup[A]): Option[A] =
if (isEmpty(fa)) None else ev.combineAllOption(toIterable(fa))

/**
* Convert F[A] to an Iterable[A].
*
* This method may be overridden for the sake of performance, but implementers should take care
* not to force a full materialization of the collection.
*/
def toIterable[A](fa: F[A]): Iterable[A] =
cats.compat.FoldableCompat.toIterable(fa)(self)

/**
* Fold implemented by mapping `A` values into `B` and then
* combining them using the given `Monoid[B]` instance.
Expand Down
1 change: 1 addition & 0 deletions core/src/main/scala/cats/syntax/foldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cats
package syntax

trait FoldableSyntax extends Foldable.ToFoldableOps with UnorderedFoldable.ToUnorderedFoldableOps {

implicit final def catsSyntaxNestedFoldable[F[_]: Foldable, G[_], A](fga: F[G[A]]): NestedFoldableOps[F, G, A] =
new NestedFoldableOps[F, G, A](fga)

Expand Down
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 @@ -214,6 +214,20 @@ abstract class FoldableSuite[F[_]: Foldable](name: String)(implicit ArbFInt: Arb
}
}

test(s"Foldable[$name].combineAllOption") {
forAll { (fa: F[Int]) =>
fa.combineAllOption should ===(fa.toList.combineAllOption)
fa.combineAllOption should ===(iterator(fa).toList.combineAllOption)
}
}

test(s"Foldable[$name].iterable") {
forAll { (fa: F[Int]) =>
fa.toIterable.toList should ===(fa.toList)
fa.toIterable.toList should ===(iterator(fa).toList)
}
}

test(s"Foldable[$name].intercalate") {
forAll { (fa: F[String], a: String) =>
fa.intercalate(a) should ===(fa.toList.mkString(a))
Expand Down

0 comments on commit 8d67ec6

Please sign in to comment.