Skip to content

Commit

Permalink
Add leftTraverse and leftSequence 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 fcf3a8d
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 3 deletions.
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/syntax/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,4 @@ trait AllSyntaxBinCompat2
with ListSyntaxBinCompat0
with ValidatedSyntaxBincompat0

trait AllSyntaxBinCompat3 extends UnorderedFoldableSyntax with Function1Syntax
trait AllSyntaxBinCompat3 extends UnorderedFoldableSyntax with Function1Syntax with BitraverseSyntaxBinCompat0
40 changes: 40 additions & 0 deletions core/src/main/scala/cats/syntax/bitraverse.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,43 @@ final class NestedBitraverseOps[F[_, _], G[_], A, B](private val fgagb: F[G[A],
def bisequence(implicit F: Bitraverse[F], G: Applicative[G]): G[F[A, B]] =
F.bisequence(fgagb)
}

trait BitraverseSyntaxBinCompat0 extends BisequenceSyntaxBinCompat0 {
implicit final def catsSyntaxBitraverseBinCompat0[F[_, _], A, B](fab: F[A, B]): BitraverseOpsBinCompat0[F, A, B] =
new BitraverseOpsBinCompat0(fab)
}

final class BitraverseOpsBinCompat0[F[_, _], A, B](private val value: F[A, B]) extends AnyVal {

/**
* 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[_], C](f: A => G[C])(implicit F: Bitraverse[F], G: Applicative[G]): G[F[C, B]] =
F.bitraverse(value)(f, G.pure)
}

trait BisequenceSyntaxBinCompat0 {
implicit final def catsSyntaxBisequenceBinCompat0[F[_, _], G[_], A, B](
fgab: F[G[A], B]
): BisequenceOpsBinCompat0[F, G, A, B] =
new BisequenceOpsBinCompat0(fgab)
}

final class BisequenceOpsBinCompat0[F[_, _], G[_], A, B](private val value: F[G[A], B]) extends AnyVal {
def leftSequence(implicit F: Bitraverse[F], G: Applicative[G]): G[F[A, B]] =
new BitraverseOpsBinCompat0(value).leftTraverse(identity)
}
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/syntax/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ package object syntax {
object bifunctor extends BifunctorSyntax
object bifoldable extends BifoldableSyntax
object binested extends BinestedSyntax
object bitraverse extends BitraverseSyntax
object bitraverse extends BitraverseSyntax with BitraverseSyntaxBinCompat0
@deprecated("use cats.syntax.semigroupal instead", "1.0.0-RC1")
object cartesian extends SemigroupalSyntax
object choice extends ChoiceSyntax
Expand Down
18 changes: 17 additions & 1 deletion laws/src/main/scala/cats/laws/BitraverseLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package cats
package laws

import cats.data.Nested
import cats.syntax.BitraverseSyntaxBinCompat0

trait BitraverseLaws[F[_, _]] extends BifoldableLaws[F] with BifunctorLaws[F] {
trait BitraverseLaws[F[_, _]] extends BifoldableLaws[F] with BifunctorLaws[F] with BitraverseSyntaxBinCompat0 {
implicit override def F: Bitraverse[F]

def bitraverseIdentity[A, B](fab: F[A, B]): IsEq[F[A, B]] =
Expand All @@ -28,6 +29,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 <-> fab.leftTraverse[Id, A](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(fab.leftTraverse(f))(f => f.leftTraverse(g))
val fg2 = fab.leftTraverse(a => Nested(G.map(f(a))(g)))

fg <-> fg2.value
}

}

object BitraverseLaws {
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 @@ -299,9 +299,14 @@ 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

val fgab = mock[F[G[A], B]]
val gfab2 = fgab.leftSequence

}

def testAlternativeMonad[F[_]: Alternative: Monad, G[_]: Foldable, H[_, _]: Bifoldable, A, B]: Unit = {
Expand Down

0 comments on commit fcf3a8d

Please sign in to comment.