Skip to content

Commit

Permalink
Optimize foldMap implementations with combineAll
Browse files Browse the repository at this point in the history
  • Loading branch information
carymrobbins committed Nov 10, 2017
1 parent aeff8a6 commit 007963d
Show file tree
Hide file tree
Showing 9 changed files with 28 additions and 2 deletions.
5 changes: 4 additions & 1 deletion alleycats-core/src/main/scala/alleycats/std/iterable.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package alleycats
package std

import cats.{Eval, Foldable}
import cats.{Eval, Foldable, Monoid}
import export._

@reexports(IterableInstances)
Expand All @@ -16,6 +16,9 @@ object IterableInstances {

override def foldRight[A, B](fa: Iterable[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
Foldable.iterateRight(fa, lb)(f)

override def foldMap[A, B](fa: Iterable[A])(f: A => B)(implicit B: Monoid[B]): B =
B.combineAll(fa.iterator.map(f))
}

}
Expand Down
3 changes: 3 additions & 0 deletions alleycats-core/src/main/scala/alleycats/std/set.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ object SetInstances {
def foldRight[A, B](fa: Set[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
Foldable.iterateRight(fa, lb)(f)

override def foldMap[A, B](fa: Set[A])(f: A => B)(implicit B: Monoid[B]): B =
B.combineAll(fa.map(f))

def traverse[G[_]: Applicative, A, B](sa: Set[A])(f: A => G[B]): G[Set[B]] = {
val G = Applicative[G]
sa.foldLeft(G.pure(Set.empty[B])) { (buf, a) =>
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/scala/cats/data/NonEmptyList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,9 @@ private[data] sealed abstract class NonEmptyListInstances extends NonEmptyListIn
override def foldRight[A, B](fa: NonEmptyList[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
fa.foldRight(lb)(f)

override def foldMap[A, B](fa: NonEmptyList[A])(f: A => B)(implicit B: Monoid[B]): B =
B.combineAll(fa.toList.iterator.map(f))

def tailRecM[A, B](a: A)(f: A => NonEmptyList[Either[A, B]]): NonEmptyList[B] = {
val buf = new ListBuffer[B]
@tailrec def go(v: NonEmptyList[Either[A, B]]): Unit = v.head match {
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/scala/cats/data/NonEmptyVector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@ private[data] sealed abstract class NonEmptyVectorInstances {
override def foldRight[A, B](fa: NonEmptyVector[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
fa.foldRight(lb)(f)

override def foldMap[A, B](fa: NonEmptyVector[A])(f: A => B)(implicit B: Monoid[B]): B =
B.combineAll(fa.toVector.iterator.map(f))

override def nonEmptyPartition[A, B, C](fa: NonEmptyVector[A])(f: (A) => Either[B, C]): Ior[NonEmptyList[B], NonEmptyList[C]] = {
import cats.syntax.either._
import cats.syntax.reducible._
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/scala/cats/instances/list.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ trait ListInstances extends cats.kernel.instances.ListInstances {
Eval.defer(loop(fa))
}

override def foldMap[A, B](fa: List[A])(f: A => B)(implicit B: Monoid[B]): B =
B.combineAll(fa.iterator.map(f))

def traverse[G[_], A, B](fa: List[A])(f: A => G[B])(implicit G: Applicative[G]): G[List[B]] =
foldRight[A, G[List[B]]](fa, Always(G.pure(List.empty))){ (a, lglb) =>
G.map2Eval(f(a), lglb)(_ :: _)
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/scala/cats/instances/queue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package cats
package instances

import cats.syntax.show._

import scala.annotation.tailrec
import scala.collection.immutable.Queue
import scala.util.Try
Expand Down Expand Up @@ -75,6 +74,9 @@ trait QueueInstances extends cats.kernel.instances.QueueInstances {
Eval.defer(loop(fa))
}

override def foldMap[A, B](fa: Queue[A])(f: A => B)(implicit B: Monoid[B]): B =
B.combineAll(fa.iterator.map(f))

def traverse[G[_], A, B](fa: Queue[A])(f: A => G[B])(implicit G: Applicative[G]): G[Queue[B]] =
foldRight[A, G[Queue[B]]](fa, Always(G.pure(Queue.empty))){ (a, lglb) =>
G.map2Eval(f(a), lglb)(_ +: _)
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/scala/cats/instances/sortedSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ trait SortedSetInstances extends SortedSetInstances1 {
def foldRight[A, B](fa: SortedSet[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
Foldable.iterateRight(fa, lb)(f)

override def foldMap[A, B](fa: SortedSet[A])(f: A => B)(implicit B: Monoid[B]): B =
B.combineAll(fa.map(f))

override def get[A](fa: SortedSet[A])(idx: Long): Option[A] = {
@tailrec
def go(idx: Int, it: Iterator[A]): Option[A] = {
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/scala/cats/instances/stream.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ trait StreamInstances extends cats.kernel.instances.StreamInstances {
if (s.isEmpty) lb else f(s.head, Eval.defer(foldRight(s.tail, lb)(f)))
}

override def foldMap[A, B](fa: Stream[A])(f: A => B)(implicit B: Monoid[B]): B =
B.combineAll(fa.iterator.map(f))

def traverse[G[_], A, B](fa: Stream[A])(f: A => G[B])(implicit G: Applicative[G]): G[Stream[B]] = {
// We use foldRight to avoid possible stack overflows. Since
// we don't want to return a Eval[_] instance, we call .value
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/scala/cats/instances/vector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ trait VectorInstances extends cats.kernel.instances.VectorInstances {
Eval.defer(loop(0))
}

override def foldMap[A, B](fa: Vector[A])(f: A => B)(implicit B: Monoid[B]): B =
B.combineAll(fa.iterator.map(f))

def tailRecM[A, B](a: A)(fn: A => Vector[Either[A, B]]): Vector[B] = {
val buf = Vector.newBuilder[B]
var state = List(fn(a).iterator)
Expand Down

0 comments on commit 007963d

Please sign in to comment.