From 76fc39ad512d07b385775d3473793f582c15798d Mon Sep 17 00:00:00 2001 From: Erica Giordo Date: Fri, 1 Jun 2018 13:00:14 +0100 Subject: [PATCH 1/4] Adding biSemiflatMap to EitherT --- core/src/main/scala/cats/data/EitherT.scala | 3 +++ .../test/scala/cats/tests/EitherTSuite.scala | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/core/src/main/scala/cats/data/EitherT.scala b/core/src/main/scala/cats/data/EitherT.scala index 748c1b029b..45bc2fe09d 100644 --- a/core/src/main/scala/cats/data/EitherT.scala +++ b/core/src/main/scala/cats/data/EitherT.scala @@ -120,6 +120,9 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { case r@Right(_) => F.pure(r.leftCast) }) + def biSemiflatMap[C, D](fa: A => F[C], fb: B => F[D])(implicit F: Monad[F]): EitherT[F, C, D] = + leftSemiflatMap(fa).semiflatMap(fb) + def compare(that: EitherT[F, A, B])(implicit o: Order[F[Either[A, B]]]): Int = o.compare(value, that.value) diff --git a/tests/src/test/scala/cats/tests/EitherTSuite.scala b/tests/src/test/scala/cats/tests/EitherTSuite.scala index b3063bddbf..dd07e45f4f 100644 --- a/tests/src/test/scala/cats/tests/EitherTSuite.scala +++ b/tests/src/test/scala/cats/tests/EitherTSuite.scala @@ -471,4 +471,22 @@ class EitherTSuite extends CatsSuite { } } + test("biSemiflatMap consistent with leftSemiflatMap and semiFlatmap") { + forAll { (eithert: EitherT[List, String, Int], fa: String => List[Int], fb: Int => List[String]) => + eithert.biSemiflatMap(fa, fb) should === (eithert.leftSemiflatMap(fa).semiflatMap(fb)) + } + } + + test("biSemiflatMap consistent with leftSemiflatMap") { + forAll { (eithert: EitherT[List, String, Int], fa: String => List[Int]) => + eithert.biSemiflatMap(fa, List(_)) should ===(eithert.leftSemiflatMap(a => fa(a))) + } + } + + test("biSemiflatMap consistent with semiflatMap") { + forAll { (eithert: EitherT[List, String, Int], fb: Int => List[String]) => + eithert.biSemiflatMap(List(_), fb) should ===(eithert.semiflatMap(b => fb(b))) + } + } + } From 596ad6e55ad653a1987f2e60435afda1d01ca3e4 Mon Sep 17 00:00:00 2001 From: Erica Giordo Date: Thu, 7 Jun 2018 12:02:50 +0100 Subject: [PATCH 2/4] Expanding leftSemiflatMap and semiflatMap --- core/src/main/scala/cats/data/EitherT.scala | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/EitherT.scala b/core/src/main/scala/cats/data/EitherT.scala index 45bc2fe09d..99c31d875e 100644 --- a/core/src/main/scala/cats/data/EitherT.scala +++ b/core/src/main/scala/cats/data/EitherT.scala @@ -121,7 +121,10 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { }) def biSemiflatMap[C, D](fa: A => F[C], fb: B => F[D])(implicit F: Monad[F]): EitherT[F, C, D] = - leftSemiflatMap(fa).semiflatMap(fb) + EitherT(F.flatMap(value) { + case Left(a) => F.map(fa(a)) { c => Left(c) } + case Right(b) => F.map(fb(b)) { d => Right(d) } + }) def compare(that: EitherT[F, A, B])(implicit o: Order[F[Either[A, B]]]): Int = o.compare(value, that.value) From 7a40d95e5f3f052e8091f2d3ac12b4fb33e3d956 Mon Sep 17 00:00:00 2001 From: Erica Giordo Date: Thu, 7 Jun 2018 17:07:31 +0100 Subject: [PATCH 3/4] Added documentation --- core/src/main/scala/cats/data/EitherT.scala | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/src/main/scala/cats/data/EitherT.scala b/core/src/main/scala/cats/data/EitherT.scala index 99c31d875e..cb2805b366 100644 --- a/core/src/main/scala/cats/data/EitherT.scala +++ b/core/src/main/scala/cats/data/EitherT.scala @@ -120,6 +120,18 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { case r@Right(_) => F.pure(r.leftCast) }) + /** Combine `leftSemiflatMap` and `semiflatMap` together. + * + * Example: + * {{{ + * scala> import cats.implicits._ + * scala> import cats.data.EitherT + * + * scala> val eitherT: EitherT[List, String, Int] = EitherT(List(Left("abc"), Right(123))) + * scala> eitherT.biSemiflatMap(string => List(string.length), int => List(int.toFloat)) + * res0: cats.data.EitherT[List,Int,Float] = EitherT(List(Left(3), Right(123.0))) + * }}} + */ def biSemiflatMap[C, D](fa: A => F[C], fb: B => F[D])(implicit F: Monad[F]): EitherT[F, C, D] = EitherT(F.flatMap(value) { case Left(a) => F.map(fa(a)) { c => Left(c) } From 7015a8287c7ead851c1f8b5aa5d99338eef4baa2 Mon Sep 17 00:00:00 2001 From: Erica Giordo Date: Fri, 8 Jun 2018 22:49:19 +0100 Subject: [PATCH 4/4] Added EitherT types for 2.10 and 2.11 --- core/src/main/scala/cats/data/EitherT.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/EitherT.scala b/core/src/main/scala/cats/data/EitherT.scala index cb2805b366..90a79138ed 100644 --- a/core/src/main/scala/cats/data/EitherT.scala +++ b/core/src/main/scala/cats/data/EitherT.scala @@ -127,7 +127,7 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { * scala> import cats.implicits._ * scala> import cats.data.EitherT * - * scala> val eitherT: EitherT[List, String, Int] = EitherT(List(Left("abc"), Right(123))) + * scala> val eitherT: EitherT[List, String, Int] = EitherT[List, String, Int](List(Left("abc"), Right(123))) * scala> eitherT.biSemiflatMap(string => List(string.length), int => List(int.toFloat)) * res0: cats.data.EitherT[List,Int,Float] = EitherT(List(Left(3), Right(123.0))) * }}}