Skip to content

Commit

Permalink
backported typelevel#2772 added foldRightDefer to Foldable
Browse files Browse the repository at this point in the history
  • Loading branch information
gagandeepkalra committed Mar 1, 2020
1 parent 29efba5 commit 5a7fa38
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 3 deletions.
12 changes: 10 additions & 2 deletions core/src/main/scala/cats/Foldable.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package cats

import scala.collection.mutable
import cats.Foldable.sentinel
import cats.instances.either._
import cats.kernel.CommutativeMonoid
import simulacrum.typeclass
import Foldable.sentinel

import scala.collection.mutable

/**
* Data structures that can be folded to a summary value.
Expand Down Expand Up @@ -594,6 +595,13 @@ object Foldable {
Eval.always(iterable.iterator).flatMap(loop)
}

def iterateRightDefer[G[_]: Defer, A, B](iterable: Iterable[A], lb: G[B])(f: (A, G[B]) => G[B]): G[B] = {
def loop(it: Iterator[A]): G[B] =
Defer[G].defer(if (it.hasNext) f(it.next(), Defer[G].defer(loop(it))) else Defer[G].defer(lb))

Defer[G].defer(loop(iterable.iterator))
}

/**
* Isomorphic to
*
Expand Down
7 changes: 7 additions & 0 deletions core/src/main/scala/cats/syntax/foldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,13 @@ final class FoldableOps0[F[_], A](private val fa: F[A]) extends AnyVal {
*/
def maximumByOption[B: Order](f: A => B)(implicit F: Foldable[F]): Option[A] =
F.maximumOption(fa)(Order.by(f))

def foldRightDefer[G[_]: Defer, B](gb: G[B])(fn: (A, G[B]) => G[B])(implicit F: Foldable[F]): G[B] =
Defer[G].defer(
F.foldLeft(fa, (z: G[B]) => z)(
(acc, elem) => z => Defer[G].defer(fn(elem, acc(z)))
)(gb)
)
}

final private[syntax] class FoldableOps1[F[_]](private val F: Foldable[F]) extends AnyVal {
Expand Down
10 changes: 10 additions & 0 deletions laws/src/main/scala/cats/laws/FoldableLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ trait FoldableLaws[F[_]] extends UnorderedFoldableLaws[F] {
): IsEq[B] =
F.foldM[Id, A, B](fa, b)(f) <-> F.foldLeft(fa, b)(f)

def foldRightDeferConsistentWithFoldRight[A, B](
fa: F[A],
f: (B, A) => B
)(implicit
M: Monoid[B]): IsEq[B] = {
val g: (A, Eval[B]) => Eval[B] = (a, ea) => ea.map(f(_, a))

F.foldRight(fa, Later(M.empty))(g).value <-> fa.foldRightDefer(Later(M.empty): Eval[B])(g).value
}

/**
* `reduceLeftOption` consistent with `reduceLeftToOption`
*/
Expand Down
3 changes: 2 additions & 1 deletion laws/src/main/scala/cats/laws/discipline/FoldableTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ trait FoldableTests[F[_]] extends UnorderedFoldableTests[F] {
"takeWhile_ reference" -> forAll(laws.takeWhile_Ref[A] _),
"dropWhile_ reference" -> forAll(laws.dropWhile_Ref[A] _),
"collectFirstSome reference" -> forAll(laws.collectFirstSome_Ref[A, B] _),
"collectFirst reference" -> forAll(laws.collectFirst_Ref[A, B] _)
"collectFirst reference" -> forAll(laws.collectFirst_Ref[A, B] _),
"foldRightDefer consistency" -> forAll(laws.foldRightDeferConsistentWithFoldRight[A, B] _)
)
}

Expand Down
7 changes: 7 additions & 0 deletions tests/src/test/scala/cats/tests/FoldableSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,13 @@ class FoldableSuiteAdditional extends CatsSuite {
// safely build large lists
val larger = F.foldRight(large, Now(List.empty[Int]))((x, lxs) => lxs.map((x + 1) :: _))
larger.value should ===(large.map(_ + 1))

val sum = large.foldRightDefer(Eval.later(0))((elem, acc) => acc.map(_ + elem))
sum.value should ===(large.sum)

def boom[A]: Eval[A] = Eval.later(sys.error("boom"))
// Ensure that the lazy param is actually handled lazily
val lazySum: Eval[Int] = large.foldRightDefer(boom[Int])((elem, acc) => acc.map(_ + elem))
}

def checkMonadicFoldsStackSafety[F[_]](fromRange: Range => F[Int])(implicit F: Foldable[F]): Unit = {
Expand Down

0 comments on commit 5a7fa38

Please sign in to comment.