Skip to content

Commit

Permalink
backported typelevel#2742 Added separateFoldable
Browse files Browse the repository at this point in the history
  • Loading branch information
gagandeepkalra committed Mar 3, 2020
1 parent 29efba5 commit 1a70a19
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 0 deletions.
24 changes: 24 additions & 0 deletions core/src/main/scala/cats/syntax/alternative.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,30 @@ final class SeparateOps[F[_], G[_, _], A, B](private val fgab: F[G[A, B]]) exten
F: Monad[F],
A: Alternative[F],
G: Bifoldable[G]): (F[A], F[B]) = A.separate[G, A, B](fgab)

/**
* Separate the inner foldable values into the "lefts" and "rights".
* A variant of [[separate]] that is specialized
* for Fs that have Foldable instances
* which allows for a single-pass implementation
* (as opposed to {{{separate}}} which is 2-pass).
*
* Example:
* {{{
* scala> import cats.implicits._
* scala> val l: List[Either[String, Int]] = List(Right(1), Left("error"))
* scala> l.separateFoldable
* res0: (List[String], List[Int]) = (List(error),List(1))
* }}}
*/
def separateFoldable(implicit AA: Alternative[F], G: Bifoldable[G], FF: Foldable[F]): (F[A], F[B]) =
FF.foldLeft(fgab, (AA.empty[A], AA.empty[B])) {
case (mamb, gab) =>
G.bifoldLeft(gab, mamb)(
(t, a) => (AA.combineK(t._1, AA.pure(a)), t._2),
(t, b) => (t._1, AA.combineK(t._2, AA.pure(b)))
)
}
}

final class GuardOps(private val condition: Boolean) extends AnyVal {
Expand Down
10 changes: 10 additions & 0 deletions tests/src/test/scala/cats/tests/AlternativeSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ class AlternativeSuite extends CatsSuite {
}
}

test("separateFoldable") {
forAll { (list: List[Either[Int, String]]) =>
val ints = list.collect { case Left(i) => i }
val strings = list.collect { case Right(s) => s }
val expected = (ints, strings)

list.separateFoldable should ===(expected)
}
}

test("guard") {
assert(Alternative[Option].guard(true).isDefined)
assert(Alternative[Option].guard(false).isEmpty)
Expand Down
5 changes: 5 additions & 0 deletions tests/src/test/scala/cats/tests/SyntaxSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,11 @@ object SyntaxSuite
val fafb = fhab.separate
}

def testAlternativeFoldable[F[_]: Alternative: Foldable, G[_]: Foldable, H[_, _]: Bifoldable, A, B]: Unit = {
val fhab = mock[F[H[A, B]]]
val fafb = fhab.separateFoldable
}

def testApplicative[F[_]: Applicative, A]: Unit = {
val a = mock[A]
val fa = a.pure[F]
Expand Down

0 comments on commit 1a70a19

Please sign in to comment.