Skip to content

Commit

Permalink
Add leftTraverse to Bitraverse typeclass
Browse files Browse the repository at this point in the history
  • Loading branch information
ikempf committed Nov 28, 2018
1 parent dc82cbd commit d72406b
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 0 deletions.
20 changes: 20 additions & 0 deletions core/src/main/scala/cats/Bitraverse.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,26 @@ import simulacrum.typeclass
*/
def bitraverse[G[_]: Applicative, A, B, C, D](fab: F[A, B])(f: A => G[C], g: B => G[D]): G[F[C, D]]

/**
* Traverse the left side of the structure with the given function.
*
* Example:
* {{{
* scala> import cats.implicits._
*
* scala> def parseInt(s: String): Option[Int] = Either.catchOnly[NumberFormatException](s.toInt).toOption
*
* scala> ("1", "2").leftTraverse(parseInt)
* res0: Option[(Int, String)] = Some((1,2))
*
* scala> ("two", "2").leftTraverse(parseInt)
* res2: Option[(Int, String)] = None
*
* }}}
*/
def leftTraverse[G[_]: Applicative, A, B, C](fab: F[A, B])(f: A => G[C]): G[F[C, B]] =
bitraverse(fab)(f, Applicative[G].pure)

/**
* Invert the structure from F[G[A], G[B]] to G[F[A, B]].
*
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/scala/cats/syntax/bitraverse.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ private[syntax] trait BitraverseSyntax1 {
final class BitraverseOps[F[_, _], A, B](private val fab: F[A, B]) extends AnyVal {
def bitraverse[G[_]: Applicative, C, D](f: A => G[C], g: B => G[D])(implicit F: Bitraverse[F]): G[F[C, D]] =
F.bitraverse(fab)(f, g)

def leftTraverse[G[_]: Applicative, C](f: A => G[C])(implicit F: Bitraverse[F]): G[F[C, B]] =
F.leftTraverse(fab)(f)
}

final class NestedBitraverseOps[F[_, _], G[_], A, B](private val fgagb: F[G[A], G[B]]) extends AnyVal {
Expand Down
15 changes: 15 additions & 0 deletions laws/src/main/scala/cats/laws/BitraverseLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@ trait BitraverseLaws[F[_, _]] extends BifoldableLaws[F] with BifunctorLaws[F] {

hi <-> c.value
}

def leftTraverseIdentity[A, B](fab: F[A, B]): IsEq[F[A, B]] =
fab <-> F.leftTraverse[Id, A, B, A](fab)(identity)

def leftTraverseCompose[G[_], A, B, C, D](
fab: F[A, B],
f: A => G[C],
g: C => G[D]
)(implicit G: Applicative[G]): IsEq[G[G[F[D, B]]]] = {
val fg = G.map(F.leftTraverse(fab)(f))(f => F.leftTraverse(f)(g))
val fg2 = F.leftTraverse(fab)(a => Nested(G.map(f(a))(g)))

fg <-> fg2.value
}

}

object BitraverseLaws {
Expand Down
1 change: 1 addition & 0 deletions tests/src/test/scala/cats/tests/SyntaxSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ object SyntaxSuite extends AllSyntaxBinCompat with AllInstances with AllSyntax {

val fab = mock[F[A, B]]
val gfcd = fab.bitraverse(f, g)
val gfcb = fab.leftTraverse(f)

val fgagb = mock[F[G[A], G[B]]]
val gfab = fgagb.bisequence
Expand Down

0 comments on commit d72406b

Please sign in to comment.