From b1e115bc98f9e7c4bd47e187ba60b2f97dbe3d79 Mon Sep 17 00:00:00 2001 From: Luka Jacobowitz Date: Sun, 28 May 2017 14:15:44 +0200 Subject: [PATCH] Replace traverse1 with more performant implementation --- core/src/main/scala/cats/data/NonEmptyList.scala | 13 +++++++------ core/src/main/scala/cats/data/NonEmptyVector.scala | 13 +++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/core/src/main/scala/cats/data/NonEmptyList.scala b/core/src/main/scala/cats/data/NonEmptyList.scala index 90f3ecec0b..b69d76e5d7 100644 --- a/core/src/main/scala/cats/data/NonEmptyList.scala +++ b/core/src/main/scala/cats/data/NonEmptyList.scala @@ -3,8 +3,6 @@ package data import cats.instances.list._ import cats.syntax.order._ -import cats.syntax.semigroup._ -import cats.syntax.cartesian._ import scala.annotation.tailrec import scala.collection.immutable.TreeSet @@ -354,10 +352,13 @@ private[data] sealed trait NonEmptyListInstances extends NonEmptyListInstances0 def extract[A](fa: NonEmptyList[A]): A = fa.head - def traverse1[G[_] : Apply, A, B](as: NonEmptyList[A])(f: A => G[B]): G[NonEmptyList[B]] = { - as.map(a => Apply[G].map(f(a))(NonEmptyList.of(_))) - .reduceLeft((acc, a) => (acc |@| a).map( _ |+| _ )) - } + def traverse1[G[_], A, B](nel: NonEmptyList[A])(f: A => G[B])(implicit G: Apply[G]): G[NonEmptyList[B]] = + Foldable[List].reduceRightToOption[A, G[List[B]]](nel.tail)(a => G.map(f(a))(_ :: Nil)) { (a, lglb) => + G.map2Eval(f(a), lglb)(_ :: _) + }.map { + case None => G.map(f(nel.head))(NonEmptyList(_, Nil)) + case Some(gtail) => G.map2(f(nel.head), gtail)(NonEmptyList(_, _)) + }.value override def traverse[G[_], A, B](fa: NonEmptyList[A])(f: A => G[B])(implicit G: Applicative[G]): G[NonEmptyList[B]] = fa traverse f diff --git a/core/src/main/scala/cats/data/NonEmptyVector.scala b/core/src/main/scala/cats/data/NonEmptyVector.scala index 1ad75bf530..e650918bf3 100644 --- a/core/src/main/scala/cats/data/NonEmptyVector.scala +++ b/core/src/main/scala/cats/data/NonEmptyVector.scala @@ -4,8 +4,6 @@ package data import scala.annotation.tailrec import scala.collection.immutable.{TreeSet, VectorBuilder} import cats.instances.vector._ -import cats.syntax.cartesian._ -import cats.syntax.semigroup._ /** * A data type which represents a `Vector` guaranteed to contain at least one element. @@ -228,10 +226,13 @@ private[data] sealed trait NonEmptyVectorInstances { def extract[A](fa: NonEmptyVector[A]): A = fa.head - def traverse1[G[_] : Apply, A, B](as: NonEmptyVector[A])(f: A => G[B]): G[NonEmptyVector[B]] = { - as.map(a => Apply[G].map(f(a))(NonEmptyVector.of(_))) - .reduceLeft((acc, a) => (acc |@| a).map( _ |+| _ )) - } + def traverse1[G[_], A, B](nel: NonEmptyVector[A])(f: A => G[B])(implicit G: Apply[G]): G[NonEmptyVector[B]] = + Foldable[Vector].reduceRightToOption[A, G[Vector[B]]](nel.tail)(a => G.map(f(a))(_ +: Vector.empty)) { (a, lglb) => + G.map2Eval(f(a), lglb)(_ +: _) + }.map { + case None => G.map(f(nel.head))(NonEmptyVector(_, Vector.empty)) + case Some(gtail) => G.map2(f(nel.head), gtail)(NonEmptyVector(_, _)) + }.value override def foldLeft[A, B](fa: NonEmptyVector[A], b: B)(f: (B, A) => B): B = fa.foldLeft(b)(f)