Skip to content

Commit

Permalink
Add size to Foldable
Browse files Browse the repository at this point in the history
Override with a more performant implementation in Map, Set, and Vector using the
size method provided by the standard library.

see #1091
  • Loading branch information
Andrea Fiore committed Jun 12, 2016
1 parent 5cf9da3 commit eafce1c
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 0 deletions.
11 changes: 11 additions & 0 deletions core/src/main/scala/cats/Foldable.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cats

import scala.collection.mutable
import cats.std.long._
import simulacrum.typeclass

/**
Expand Down Expand Up @@ -56,6 +57,16 @@ import simulacrum.typeclass
}
}

/**
* The size of this Foldable.
*
* This is overriden in structures that have more efficient size implementations
* (e.g. Vector, Set, Map).
*
* Note: will not terminate for infinite-sized collections.
*/
def size[A](fa: F[A]): Long = foldMap(fa)(_ => 1)

/**
* Fold implemented using the given Monoid[A] instance.
*/
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/std/map.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ trait MapInstances extends cats.kernel.std.MapInstances {
def foldRight[A, B](fa: Map[K, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
Foldable.iterateRight(fa.values.iterator, lb)(f)

override def size[A](fa: Map[K, A]): Long = fa.size.toLong

override def isEmpty[A](fa: Map[K, A]): Boolean = fa.isEmpty
}
}
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/std/set.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ trait SetInstances extends cats.kernel.std.SetInstances {
def foldRight[A, B](fa: Set[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
Foldable.iterateRight(fa.iterator, lb)(f)

override def size[A](fa: Set[A]): Long = fa.size.toLong

override def exists[A](fa: Set[A])(p: A => Boolean): Boolean =
fa.exists(p)

Expand Down
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/std/vector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ trait VectorInstances extends cats.kernel.std.VectorInstances {
Eval.defer(loop(0))
}

override def size[A](fa: Vector[A]): Long = fa.size.toLong

def traverse[G[_], A, B](fa: Vector[A])(f: A => G[B])(implicit G: Applicative[G]): G[Vector[B]] =
foldRight[A, G[Vector[B]]](fa, Always(G.pure(Vector.empty))){ (a, lgvb) =>
G.map2Eval(f(a), lgvb)(_ +: _)
Expand Down
6 changes: 6 additions & 0 deletions tests/src/test/scala/cats/tests/FoldableTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ abstract class FoldableCheck[F[_]: Foldable](name: String)(implicit ArbFInt: Arb

def iterator[T](fa: F[T]): Iterator[T]

test("size") {
forAll { (fa: F[Int]) =>
fa.size should === (iterator(fa).size.toLong)
}
}

test("summation") {
forAll { (fa: F[Int]) =>
val total = iterator(fa).sum
Expand Down

0 comments on commit eafce1c

Please sign in to comment.