Skip to content

Commit

Permalink
Adding apply and get for Foldable
Browse files Browse the repository at this point in the history
  • Loading branch information
yilinwei committed Nov 13, 2016
1 parent bffd31f commit cc8e7c9
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 3 deletions.
20 changes: 20 additions & 0 deletions core/src/main/scala/cats/Foldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,26 @@ import simulacrum.typeclass
*/
def size[A](fa: F[A]): Long = foldMap(fa)(_ => 1)

/**
* Get the element at the index of the `Foldable`.
*
* The default implementation of this is based on `foldLeft`, and thus will
* always fold across the entire structure.
*/
def get[A](fa: F[A])(idx: Long): Option[A] =
foldLeft(fa, (0L, Option.empty[A])) { (b, a) =>
b._1 match {
case i if i == idx => (i + 1, Some(a))
case i if i < idx => (i + 1, None)
case _ => b
}
}._2

/**
* Get the element at the index of the `Foldable`
*/
def apply[A](fa: F[A])(idx: Long): A = get(fa)(idx).get

/**
* Fold implemented using the given Monoid[A] instance.
*/
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/scala/cats/instances/vector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ trait VectorInstances extends cats.kernel.instances.VectorInstances {

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

override def get[A](fa: Vector[A])(idx: Long): Option[A] = if (fa.size > idx && idx > 0) Some(fa(idx.toInt)) else None

override 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
13 changes: 10 additions & 3 deletions tests/src/test/scala/cats/tests/FoldableTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,16 @@ 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("size/get/apply") {
forAll { (fa: F[Int], n: Int) =>
val s = fa.size
s should === (iterator(fa).size.toLong)
if(n < s && n > 0) {
fa(n.toLong) === (iterator(fa).take(n + 1).toList.last)
fa.get(n.toLong) === Some(fa(n.toLong))
} else {
fa.get(n.toLong) === None
}
}
}

Expand Down

0 comments on commit cc8e7c9

Please sign in to comment.