Skip to content

Commit

Permalink
remove iteratorFoldM fixes typelevel#1716
Browse files Browse the repository at this point in the history
  • Loading branch information
kailuowang committed Jun 23, 2017
1 parent e3a969e commit 33352a2
Show file tree
Hide file tree
Showing 9 changed files with 10 additions and 65 deletions.
35 changes: 0 additions & 35 deletions core/src/main/scala/cats/Foldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -414,41 +414,6 @@ object Foldable {
loop()
}

/**
* Implementation of [[Foldable.foldM]] which can short-circuit for
* structures with an `Iterator`.
*
* For example we can sum a `Stream` of integers and stop if
* the sum reaches 100 (if we reach the end of the `Stream`
* before getting to 100 we return the total sum) :
*
* {{{
* scala> import cats.implicits._
* scala> type LongOr[A] = Either[Long, A]
* scala> def sumStream(s: Stream[Int]): Long =
* | Foldable.iteratorFoldM[LongOr, Int, Long](s.toIterator, 0L){ (acc, n) =>
* | val sum = acc + n
* | if (sum < 100L) Right(sum) else Left(sum)
* | }.merge
*
* scala> sumStream(Stream.continually(1))
* res0: Long = 100
*
* scala> sumStream(Stream(1,2,3,4))
* res1: Long = 10
* }}}
*
* Note that `Foldable[Stream].foldM` uses this method underneath, so
* you wouldn't call this method explicitly like in the example above.
*/
def iteratorFoldM[M[_], A, B](it: Iterator[A], z: B)(f: (B, A) => M[B])(implicit M: Monad[M]): M[B] = {
val go: B => M[Either[B, B]] = { b =>
if (it.hasNext) M.map(f(b, it.next))(Left(_))
else M.pure(Right(b))
}
M.tailRecM(z)(go)
}


/**
* Isomorphic to
Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/cats/data/NonEmptyList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,6 @@ private[data] sealed trait NonEmptyListInstances extends NonEmptyListInstances0
override def fold[A](fa: NonEmptyList[A])(implicit A: Monoid[A]): A =
fa.reduce

override def foldM[G[_], A, B](fa: NonEmptyList[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] =
Foldable.iteratorFoldM(fa.toList.toIterator, z)(f)

override def find[A](fa: NonEmptyList[A])(f: A => Boolean): Option[A] =
fa find f

Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/cats/data/NonEmptyVector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,6 @@ private[data] sealed trait NonEmptyVectorInstances {
override def fold[A](fa: NonEmptyVector[A])(implicit A: Monoid[A]): A =
fa.reduce

override def foldM[G[_], A, B](fa: NonEmptyVector[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] =
Foldable.iteratorFoldM(fa.toVector.toIterator, z)(f)

override def find[A](fa: NonEmptyVector[A])(f: A => Boolean): Option[A] =
fa.find(f)

Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/cats/instances/list.scala
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,6 @@ trait ListInstances extends cats.kernel.instances.ListInstances {

override def filter[A](fa: List[A])(f: A => Boolean): List[A] = fa.filter(f)

override def foldM[G[_], A, B](fa: List[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] =
Foldable.iteratorFoldM(fa.toIterator, z)(f)

override def fold[A](fa: List[A])(implicit A: Monoid[A]): A = A.combineAll(fa)

override def toList[A](fa: List[A]): List[A] = fa
Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/cats/instances/map.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,6 @@ trait MapInstances extends cats.kernel.instances.MapInstances {

override def isEmpty[A](fa: Map[K, A]): Boolean = fa.isEmpty

override def foldM[G[_], A, B](fa: Map[K, A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] =
Foldable.iteratorFoldM(fa.valuesIterator, z)(f)

override def fold[A](fa: Map[K, A])(implicit A: Monoid[A]): A =
A.combineAll(fa.values)

Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/cats/instances/set.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ trait SetInstances extends cats.kernel.instances.SetInstances {

override def isEmpty[A](fa: Set[A]): Boolean = fa.isEmpty

override def foldM[G[_], A, B](fa: Set[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] =
Foldable.iteratorFoldM(fa.toIterator, z)(f)

override def fold[A](fa: Set[A])(implicit A: Monoid[A]): A = A.combineAll(fa)

override def toList[A](fa: Set[A]): List[A] = fa.toList
Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/cats/instances/stream.scala
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,6 @@ trait StreamInstances extends cats.kernel.instances.StreamInstances {

override def collect[A, B](fa: Stream[A])(f: PartialFunction[A, B]): Stream[B] = fa.collect(f)

override def foldM[G[_], A, B](fa: Stream[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] =
Foldable.iteratorFoldM(fa.toIterator, z)(f)

override def fold[A](fa: Stream[A])(implicit A: Monoid[A]): A = A.combineAll(fa)

override def toList[A](fa: Stream[A]): List[A] = fa.toList
Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/cats/instances/vector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,6 @@ trait VectorInstances extends cats.kernel.instances.VectorInstances {

override def collect[A, B](fa: Vector[A])(f: PartialFunction[A, B]): Vector[B] = fa.collect(f)

override def foldM[G[_], A, B](fa: Vector[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] =
Foldable.iteratorFoldM(fa.toIterator, z)(f)

override def fold[A](fa: Vector[A])(implicit A: Monoid[A]): A = A.combineAll(fa)

override def toList[A](fa: Vector[A]): List[A] = fa.toList
Expand Down
19 changes: 10 additions & 9 deletions tests/src/test/scala/cats/tests/FoldableTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,7 @@ class FoldableTestsAdditional extends CatsSuite {
}
assert(result.value)

// test trampolining
val large = Stream((1 to 10000): _*)
assert(contains(large, 10000).value)

// test laziness of foldM
dangerous.foldM(0)((acc, a) => if (a < 2) Some(acc + a) else None) should === (None)
}

test(".foldLeftM short-circuiting") {
Expand All @@ -214,17 +209,23 @@ class FoldableTestsAdditional extends CatsSuite {
}

test(".foldLeftM short-circuiting optimality") {
// test that no more elements are evaluated than absolutely necessary
// test that no more than 1 elements are evaluated than absolutely necessary

def concatUntil(ss: Stream[String], stop: String): Either[String, String] =
Foldable[Stream].foldLeftM[Either[String, ?], String, String](ss, "") { (acc, s) =>
if (s == stop) Left(acc) else Right(acc + s)
}

def boom: Stream[String] = sys.error("boom")
assert(concatUntil("STOP" #:: boom, "STOP") == Left(""))
assert(concatUntil("Zero" #:: "STOP" #:: boom, "STOP") == Left("Zero"))
assert(concatUntil("Zero" #:: "One" #:: "STOP" #:: boom, "STOP") == Left("ZeroOne"))
assert(concatUntil("STOP" #:: "AFTER" #:: boom, "STOP") == Left(""))
assert(concatUntil("Zero" #:: "STOP" #:: "AFTER" #:: boom, "STOP") == Left("Zero"))
assert(concatUntil("Zero" #:: "One" #:: "STOP" #:: "AFTER" #:: boom, "STOP") == Left("ZeroOne"))
}

test("Foldable[List] doesn't break substitution") {
val result = List.range(0,10).foldM(List.empty[Int])((accum, elt) => Eval.always(elt :: accum))

assert(result.value == result.value)
}
}

Expand Down

0 comments on commit 33352a2

Please sign in to comment.