Skip to content

Commit

Permalink
Merge pull request #1520 from peterneyens/foldable-intercalate
Browse files Browse the repository at this point in the history
Add Foldable.intercalate
  • Loading branch information
adelbertc authored Jan 7, 2017
2 parents ec0af6e + d02699e commit fd15e07
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 2 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 @@ -386,6 +386,26 @@ import simulacrum.typeclass
def nonEmpty[A](fa: F[A]): Boolean =
!isEmpty(fa)

/**
* Intercalate/insert an element between the existing elements while folding.
*
* {{{
* scala> import cats.implicits._
* scala> Foldable[List].intercalate(List("a","b","c"), "-")
* res0: String = a-b-c
* scala> Foldable[List].intercalate(List("a"), "-")
* res1: String = a
* scala> Foldable[List].intercalate(List.empty[String], "-")
* res2: String = ""
* scala> Foldable[Vector].intercalate(Vector(1,2,3), 1)
* res3: Int = 8
* }}}
*/
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)

def compose[G[_]: Foldable]: Foldable[λ[α => F[G[α]]]] =
new ComposedFoldable[F, G] {
val F = self
Expand Down
19 changes: 19 additions & 0 deletions core/src/main/scala/cats/Reducible.scala
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,25 @@ import simulacrum.typeclass

def maximum[A](fa: F[A])(implicit A: Order[A]): A =
reduceLeft(fa)(A.max)

/**
* Intercalate/insert an element between the existing elements while reducing.
*
* {{{
* scala> import cats.implicits._
* scala> import cats.data.NonEmptyList
* scala> val nel = NonEmptyList.of("a", "b", "c")
* scala> Reducible[NonEmptyList].intercalate1(nel, "-")
* res0: String = a-b-c
* scala> Reducible[NonEmptyList].intercalate1(NonEmptyList.of("a"), "-")
* res1: String = a
* }}}
*/
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)
}

/**
Expand Down
8 changes: 7 additions & 1 deletion tests/src/test/scala/cats/tests/FoldableTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import org.scalacheck.Arbitrary

import cats.instances.all._

abstract class FoldableCheck[F[_]: Foldable](name: String)(implicit ArbFInt: Arbitrary[F[Int]]) extends CatsSuite with PropertyChecks {
abstract class FoldableCheck[F[_]: Foldable](name: String)(implicit ArbFInt: Arbitrary[F[Int]], ArbFString: Arbitrary[F[String]]) extends CatsSuite with PropertyChecks {

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

Expand Down Expand Up @@ -67,6 +67,12 @@ abstract class FoldableCheck[F[_]: Foldable](name: String)(implicit ArbFInt: Arb
fa.reduceRightOption((x, ly) => ly.map(x - _)).value should === (list.reduceRightOption(_ - _))
}
}

test("intercalate") {
forAll { (fa: F[String], a: String) =>
fa.intercalate(a) should === (fa.toList.mkString(a))
}
}
}

class FoldableTestsAdditional extends CatsSuite {
Expand Down
8 changes: 7 additions & 1 deletion tests/src/test/scala/cats/tests/ReducibleTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class ReducibleTestsAdditional extends CatsSuite {

}

abstract class ReducibleCheck[F[_]: Reducible](name: String)(implicit ArbFInt: Arbitrary[F[Int]]) extends FoldableCheck[F](name) {
abstract class ReducibleCheck[F[_]: Reducible](name: String)(implicit ArbFInt: Arbitrary[F[Int]], ArbFString: Arbitrary[F[String]]) extends FoldableCheck[F](name) {
def range(start: Long, endInclusive: Long): F[Long]

test(s"Reducible[$name].reduceLeftM stack safety") {
Expand All @@ -80,4 +80,10 @@ abstract class ReducibleCheck[F[_]: Reducible](name: String)(implicit ArbFInt: A
fa.toList.toNel should === (Some(fa.toNonEmptyList))
}
}

test(s"Reducible[$name].intercalate1") {
forAll { (fa: F[String], a: String) =>
fa.intercalate1(a) === (fa.toList.mkString(a))
}
}
}

0 comments on commit fd15e07

Please sign in to comment.