diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index d90294e530..5ea749a5e6 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -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 /** diff --git a/tests/src/test/scala/cats/tests/FoldableTests.scala b/tests/src/test/scala/cats/tests/FoldableTests.scala index 2e8a6d8b63..2fb1eff709 100644 --- a/tests/src/test/scala/cats/tests/FoldableTests.scala +++ b/tests/src/test/scala/cats/tests/FoldableTests.scala @@ -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] @@ -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) } } @@ -96,3 +101,23 @@ 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 FoldableMapCheck extends FoldableCheck[Map[Int, ?]]("map") { + def iterator[T](map: Map[Int, T]): Iterator[T] = map.iterator.map(_._2) +}