From a75ec62a563d362c1748e24eb817031a6cea7acc Mon Sep 17 00:00:00 2001 From: peterneyens Date: Mon, 9 Jan 2017 20:49:11 +0100 Subject: [PATCH 1/2] Update Foldable/Reducible intercalate to reduce complexity --- core/src/main/scala/cats/Foldable.scala | 17 ++++++++++++++--- core/src/main/scala/cats/Reducible.scala | 9 +++++---- .../main/scala/cats/data/NonEmptyVector.scala | 5 +++++ core/src/main/scala/cats/instances/list.scala | 2 ++ core/src/main/scala/cats/instances/set.scala | 2 ++ core/src/main/scala/cats/instances/stream.scala | 2 ++ core/src/main/scala/cats/instances/vector.scala | 2 ++ 7 files changed, 32 insertions(+), 7 deletions(-) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index 71b45f1be4..86f386d1e5 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -402,9 +402,20 @@ import simulacrum.typeclass * }}} */ def intercalate[A](fa: F[A], a: A)(implicit A: Monoid[A]): A = - reduceLeftOption(fa){ (acc, aa) => - A.combine(acc, A.combine(a, aa)) - }.getOrElse(A.empty) + A.combineAll(intersperseList(toList(fa), a)) + + protected def intersperseList[A](xs: List[A], x: A): List[A] = { + val bld = List.newBuilder[A] + val it = xs.iterator + if (it.hasNext) { + bld += it.next + while(it.hasNext) { + bld += x + bld += it.next + } + } + bld.result + } def compose[G[_]: Foldable]: Foldable[λ[α => F[G[α]]]] = new ComposedFoldable[F, G] { diff --git a/core/src/main/scala/cats/Reducible.scala b/core/src/main/scala/cats/Reducible.scala index 3dfab8fbba..ddf0014c2b 100644 --- a/core/src/main/scala/cats/Reducible.scala +++ b/core/src/main/scala/cats/Reducible.scala @@ -171,10 +171,11 @@ import simulacrum.typeclass * }}} */ def intercalate1[A](fa: F[A], a: A)(implicit A: Semigroup[A]): A = - reduceLeft(fa)((acc, aa) => A.combine(acc, A.combine(a, aa))) - - override def intercalate[A](fa: F[A], a: A)(implicit A: Monoid[A]): A = - intercalate1(fa, a) + toNonEmptyList(fa) match { + case NonEmptyList(hd, Nil) => hd + case NonEmptyList(hd, tl) => + Reducible[NonEmptyList].reduce(NonEmptyList(hd, a :: intersperseList(tl, a))) + } } /** diff --git a/core/src/main/scala/cats/data/NonEmptyVector.scala b/core/src/main/scala/cats/data/NonEmptyVector.scala index 1fff51411e..fbac4f1a1b 100644 --- a/core/src/main/scala/cats/data/NonEmptyVector.scala +++ b/core/src/main/scala/cats/data/NonEmptyVector.scala @@ -250,6 +250,11 @@ private[data] sealed trait NonEmptyVectorInstances { go(f(a)) NonEmptyVector.fromVectorUnsafe(buf.result()) } + + override def toList[A](fa: NonEmptyVector[A]): List[A] = fa.toVector.toList + + override def toNonEmptyList[A](fa: NonEmptyVector[A]): NonEmptyList[A] = + NonEmptyList(fa.head, fa.tail.toList) } implicit def catsDataEqForNonEmptyVector[A](implicit A: Eq[A]): Eq[NonEmptyVector[A]] = diff --git a/core/src/main/scala/cats/instances/list.scala b/core/src/main/scala/cats/instances/list.scala index 343e534cdc..048623ccc1 100644 --- a/core/src/main/scala/cats/instances/list.scala +++ b/core/src/main/scala/cats/instances/list.scala @@ -82,6 +82,8 @@ trait ListInstances extends cats.kernel.instances.ListInstances { override def foldM[G[_], A, B](fa: List[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] = Foldable.iteratorFoldM(fa.toIterator, z)(f) + + override def toList[A](fa: List[A]): List[A] = fa } implicit def catsStdShowForList[A:Show]: Show[List[A]] = diff --git a/core/src/main/scala/cats/instances/set.scala b/core/src/main/scala/cats/instances/set.scala index 7b376fb5e3..4a568ada14 100644 --- a/core/src/main/scala/cats/instances/set.scala +++ b/core/src/main/scala/cats/instances/set.scala @@ -30,6 +30,8 @@ trait SetInstances extends cats.kernel.instances.SetInstances { override def foldM[G[_], A, B](fa: Set[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] = Foldable.iteratorFoldM(fa.toIterator, z)(f) + + override def toList[A](fa: Set[A]): List[A] = fa.toList } implicit def catsStdShowForSet[A:Show]: Show[Set[A]] = new Show[Set[A]] { diff --git a/core/src/main/scala/cats/instances/stream.scala b/core/src/main/scala/cats/instances/stream.scala index 6fdd95cd8a..5ae8927793 100644 --- a/core/src/main/scala/cats/instances/stream.scala +++ b/core/src/main/scala/cats/instances/stream.scala @@ -109,6 +109,8 @@ trait StreamInstances extends cats.kernel.instances.StreamInstances { override def foldM[G[_], A, B](fa: Stream[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] = Foldable.iteratorFoldM(fa.toIterator, z)(f) + + override def toList[A](fa: Stream[A]): List[A] = fa.toList } implicit def catsStdShowForStream[A: Show]: Show[Stream[A]] = diff --git a/core/src/main/scala/cats/instances/vector.scala b/core/src/main/scala/cats/instances/vector.scala index dfde5b10f7..6b852a90f6 100644 --- a/core/src/main/scala/cats/instances/vector.scala +++ b/core/src/main/scala/cats/instances/vector.scala @@ -89,6 +89,8 @@ trait VectorInstances extends cats.kernel.instances.VectorInstances { override def foldM[G[_], A, B](fa: Vector[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] = Foldable.iteratorFoldM(fa.toIterator, z)(f) + + override def toList[A](fa: Vector[A]): List[A] = fa.toList } implicit def catsStdShowForVector[A:Show]: Show[Vector[A]] = From b723dea0ae0cae278e0b79503e6ae0e642ac4b5f Mon Sep 17 00:00:00 2001 From: peterneyens Date: Tue, 10 Jan 2017 20:38:59 +0100 Subject: [PATCH 2/2] Override Foldable.fold for TraversableOnce subtypes --- core/src/main/scala/cats/data/NonEmptyList.scala | 9 +++++++++ core/src/main/scala/cats/instances/list.scala | 2 ++ core/src/main/scala/cats/instances/map.scala | 5 +++++ core/src/main/scala/cats/instances/set.scala | 2 ++ core/src/main/scala/cats/instances/stream.scala | 2 ++ core/src/main/scala/cats/instances/vector.scala | 2 ++ 6 files changed, 22 insertions(+) diff --git a/core/src/main/scala/cats/data/NonEmptyList.scala b/core/src/main/scala/cats/data/NonEmptyList.scala index 69524cd174..3f8da9917e 100644 --- a/core/src/main/scala/cats/data/NonEmptyList.scala +++ b/core/src/main/scala/cats/data/NonEmptyList.scala @@ -109,6 +109,12 @@ final case class NonEmptyList[+A](head: A, tail: List[A]) { def reduceLeft[AA >: A](f: (AA, AA) => AA): AA = tail.foldLeft[AA](head)(f) + /** + * Reduce using the `Semigroup` of `AA`. + */ + def reduce[AA >: A](implicit S: Semigroup[AA]): AA = + S.combineAllOption(toList).get + def traverse[G[_], B](f: A => G[B])(implicit G: Applicative[G]): G[NonEmptyList[B]] = G.map2Eval(f(head), Always(Traverse[List].traverse(tail)(f)))(NonEmptyList(_, _)).value @@ -239,6 +245,9 @@ private[data] sealed trait NonEmptyListInstances extends NonEmptyListInstances0 override def reduceLeft[A](fa: NonEmptyList[A])(f: (A, A) => A): A = fa.reduceLeft(f) + override def reduce[A](fa: NonEmptyList[A])(implicit A: Semigroup[A]): A = + fa.reduce + override def map[A, B](fa: NonEmptyList[A])(f: A => B): NonEmptyList[B] = fa map f diff --git a/core/src/main/scala/cats/instances/list.scala b/core/src/main/scala/cats/instances/list.scala index 048623ccc1..226b9847b9 100644 --- a/core/src/main/scala/cats/instances/list.scala +++ b/core/src/main/scala/cats/instances/list.scala @@ -83,6 +83,8 @@ trait ListInstances extends cats.kernel.instances.ListInstances { override def foldM[G[_], A, B](fa: List[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] = Foldable.iteratorFoldM(fa.toIterator, z)(f) + override def fold[A](fa: List[A])(implicit A: Monoid[A]): A = A.combineAll(fa) + override def toList[A](fa: List[A]): List[A] = fa } diff --git a/core/src/main/scala/cats/instances/map.scala b/core/src/main/scala/cats/instances/map.scala index 149432cae8..a9133815d8 100644 --- a/core/src/main/scala/cats/instances/map.scala +++ b/core/src/main/scala/cats/instances/map.scala @@ -81,6 +81,11 @@ trait MapInstances extends cats.kernel.instances.MapInstances { override def foldM[G[_], A, B](fa: Map[K, A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] = Foldable.iteratorFoldM(fa.valuesIterator, z)(f) + + override def fold[A](fa: Map[K, A])(implicit A: Monoid[A]): A = + A.combineAll(fa.values) + + override def toList[A](fa: Map[K, A]): List[A] = fa.values.toList } // scalastyle:on method.length } diff --git a/core/src/main/scala/cats/instances/set.scala b/core/src/main/scala/cats/instances/set.scala index 4a568ada14..0e07f81ccb 100644 --- a/core/src/main/scala/cats/instances/set.scala +++ b/core/src/main/scala/cats/instances/set.scala @@ -31,6 +31,8 @@ trait SetInstances extends cats.kernel.instances.SetInstances { override def foldM[G[_], A, B](fa: Set[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] = Foldable.iteratorFoldM(fa.toIterator, z)(f) + override def fold[A](fa: Set[A])(implicit A: Monoid[A]): A = A.combineAll(fa) + override def toList[A](fa: Set[A]): List[A] = fa.toList } diff --git a/core/src/main/scala/cats/instances/stream.scala b/core/src/main/scala/cats/instances/stream.scala index 5ae8927793..3a2d4628ef 100644 --- a/core/src/main/scala/cats/instances/stream.scala +++ b/core/src/main/scala/cats/instances/stream.scala @@ -110,6 +110,8 @@ trait StreamInstances extends cats.kernel.instances.StreamInstances { override def foldM[G[_], A, B](fa: Stream[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] = Foldable.iteratorFoldM(fa.toIterator, z)(f) + override def fold[A](fa: Stream[A])(implicit A: Monoid[A]): A = A.combineAll(fa) + override def toList[A](fa: Stream[A]): List[A] = fa.toList } diff --git a/core/src/main/scala/cats/instances/vector.scala b/core/src/main/scala/cats/instances/vector.scala index 6b852a90f6..70da7b8b0b 100644 --- a/core/src/main/scala/cats/instances/vector.scala +++ b/core/src/main/scala/cats/instances/vector.scala @@ -90,6 +90,8 @@ trait VectorInstances extends cats.kernel.instances.VectorInstances { override def foldM[G[_], A, B](fa: Vector[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] = Foldable.iteratorFoldM(fa.toIterator, z)(f) + override def fold[A](fa: Vector[A])(implicit A: Monoid[A]): A = A.combineAll(fa) + override def toList[A](fa: Vector[A]): List[A] = fa.toList }