Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Foldabe#dropWhile_ bug. #623

Merged
merged 3 commits into from
Nov 13, 2015
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion core/src/main/scala/cats/Foldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,22 @@ import simulacrum.typeclass
if (p(a)) buf += a else buf
}.toList

/**
* Convert F[A] to a List[A], retaining only initial elements which
* match `p`.
*/
def takeWhile_[A](fa: F[A])(p: A => Boolean): List[A] =
foldRight(fa, Now(List.empty[A])) { (a, llst) =>
if (p(a)) llst.map(a :: _) else Now(Nil)
}.value

/**
* Convert F[A] to a List[A], dropping all initial elements which
* match `p`.
*/
def dropWhile_[A](fa: F[A])(p: A => Boolean): List[A] =
foldLeft(fa, mutable.ListBuffer.empty[A]) { (buf, a) =>
if (buf.nonEmpty || p(a)) buf += a else buf
if (buf.nonEmpty || !p(a)) buf += a else buf
}.toList

/**
Expand Down
1 change: 1 addition & 0 deletions core/src/main/scala/cats/std/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ trait AllInstances
with SetInstances
with StreamInstances
with VectorInstances
with IterableInstances
with AnyValInstances
with MapInstances
with BigIntInstances
Expand Down
18 changes: 18 additions & 0 deletions core/src/main/scala/cats/std/iterable.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cats
package std

trait IterableInstances {
implicit val iterableInstance: Foldable[Iterable] =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this belong in cats core? In a recent gitter conversation, the consensus was to put IndexedSeq instances in alleycats because IndexedSeq can potentially be mutable. Wouldn't the same arguments apply to Iterable?

new Foldable[Iterable] {

def foldLeft[A, B](fa: Iterable[A], b: B)(f: (B, A) => B): B =
fa.foldLeft(b)(f)

def foldRight[A, B](fa: Iterable[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = {
val it = fa.iterator
def loop(): Eval[B] =
if (it.hasNext) f(it.next, Eval.defer(loop())) else lb
Eval.defer(loop())
}
}
}
1 change: 1 addition & 0 deletions core/src/main/scala/cats/std/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ package object std {
object vector extends VectorInstances
object map extends MapInstances
object future extends FutureInstances
object iterable extends IterableInstances

object string extends StringInstances
object int extends IntInstances
Expand Down
29 changes: 29 additions & 0 deletions tests/src/test/scala/cats/tests/FoldableTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import org.scalatest.prop.PropertyChecks
import org.scalacheck.{Arbitrary, Gen}
import org.scalacheck.Arbitrary.arbitrary

import cats.data.Streaming
import cats.std.all._
import cats.laws.discipline.arbitrary._

abstract class FoldableCheck[F[_]: Foldable](name: String)(implicit ArbFInt: Arbitrary[F[Int]]) extends CatsSuite with PropertyChecks {

def iterator[T](fa: F[T]): Iterator[T]
Expand All @@ -26,6 +30,7 @@ abstract class FoldableCheck[F[_]: Foldable](name: String)(implicit ArbFInt: Arb
fa.forall(_ > n) should === (iterator(fa).forall(_ > n))
fa.filter_(_ > n) should === (iterator(fa).filter(_ > n).toList)
fa.dropWhile_(_ > n) should === (iterator(fa).dropWhile(_ > n).toList)
fa.takeWhile_(_ > n) should === (iterator(fa).takeWhile(_ > n).toList)
}
}

Expand Down Expand Up @@ -96,3 +101,27 @@ class FoldableTestsAdditional extends CatsSuite {
assert(dangerous.toStreaming.take(3).toList == List(0, 1, 2))
}
}

class FoldableListCheck extends FoldableCheck[List]("list") {
def iterator[T](list: List[T]): Iterator[T] = list.iterator
}

class FoldableVectorCheck extends FoldableCheck[Vector]("vector") {
def iterator[T](vector: Vector[T]): Iterator[T] = vector.iterator
}

class FoldableStreamCheck extends FoldableCheck[Stream]("stream") {
def iterator[T](stream: Stream[T]): Iterator[T] = stream.iterator
}

class FoldableStreamingCheck extends FoldableCheck[Streaming]("streaming") {
def iterator[T](streaming: Streaming[T]): Iterator[T] = streaming.iterator
}

class FoldableIterableCheck extends FoldableCheck[Iterable]("iterable") {
def iterator[T](iterable: Iterable[T]): Iterator[T] = iterable.iterator
}

class FoldableMapCheck extends FoldableCheck[Map[Int, ?]]("map") {
def iterator[T](map: Map[Int, T]): Iterator[T] = map.iterator.map(_._2)
}