From 344e232522d77c4189b4c834f611a669489a813d Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Wed, 8 Mar 2017 00:46:03 -0500 Subject: [PATCH 01/11] Added MonadError instance for Ior --- core/src/main/scala/cats/data/Ior.scala | 83 +++++++++++++++---------- 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/core/src/main/scala/cats/data/Ior.scala b/core/src/main/scala/cats/data/Ior.scala index 8b79aa013a..0b80f5c839 100644 --- a/core/src/main/scala/cats/data/Ior.scala +++ b/core/src/main/scala/cats/data/Ior.scala @@ -140,7 +140,7 @@ object Ior extends IorInstances with IorFunctions { final case class Both[+A, +B](a: A, b: B) extends (A Ior B) } -private[data] sealed abstract class IorInstances extends IorInstances0 { +private[data] sealed abstract class IorInstances { implicit def catsDataEqForIor[A: Eq, B: Eq]: Eq[A Ior B] = new Eq[A Ior B] { def eqv(x: A Ior B, y: A Ior B): Boolean = x === y } @@ -153,26 +153,57 @@ private[data] sealed abstract class IorInstances extends IorInstances0 { def combine(x: Ior[A, B], y: Ior[A, B]) = x.append(y) } - implicit def catsDataMonadForIor[A: Semigroup]: Monad[A Ior ?] = new Monad[A Ior ?] { - def pure[B](b: B): A Ior B = Ior.right(b) - def flatMap[B, C](fa: A Ior B)(f: B => A Ior C): A Ior C = fa.flatMap(f) - def tailRecM[B, C](b: B)(fn: B => Ior[A, Either[B, C]]): A Ior C = { - @tailrec - def loop(v: Ior[A, Either[B, C]]): A Ior C = v match { - case Ior.Left(a) => Ior.left(a) - case Ior.Right(Right(c)) => Ior.right(c) - case Ior.Both(a, Right(c)) => Ior.both(a, c) - case Ior.Right(Left(b)) => loop(fn(b)) - case Ior.Both(a, Left(b)) => - fn(b) match { - case Ior.Left(aa) => Ior.left(Semigroup[A].combine(a, aa)) - case Ior.Both(aa, x) => loop(Ior.both(Semigroup[A].combine(a, aa), x)) - case Ior.Right(x) => loop(Ior.both(a, x)) - } + // scalastyle:off method.length + implicit def catsDataMonadErrorForIor[A: Semigroup]: MonadError[Ior[A, ?], A] with Traverse[Ior[A, ?]] = + new MonadError[Ior[A, ?], A] with Traverse[Ior[A, ?]] { + + def raiseError[B](e: A): Ior[A, B] = Ior.left(e) + + def handleErrorWith[B](fa: Ior[A, B])(f: (A) => Ior[A, B]): Ior[A, B] = + fa match { + case Ior.Left(e) => f(e) + case r @ Ior.Right(_) => r + case Ior.Both(e, _) => f(e) + } + + def flatMap[B, C](fa: Ior[A, B])(f: B => Ior[A, C]): Ior[A, C] = fa.flatMap(f) + + def tailRecM[B, C](b: B)(fn: B => Ior[A, Either[B, C]]): A Ior C = { + @tailrec + def loop(v: Ior[A, Either[B, C]]): A Ior C = v match { + case Ior.Left(a) => Ior.left(a) + case Ior.Right(Right(c)) => Ior.right(c) + case Ior.Both(a, Right(c)) => Ior.both(a, c) + case Ior.Right(Left(b)) => loop(fn(b)) + case Ior.Both(a, Left(b)) => + fn(b) match { + case Ior.Left(aa) => Ior.left(Semigroup[A].combine(a, aa)) + case Ior.Both(aa, x) => loop(Ior.both(Semigroup[A].combine(a, aa), x)) + case Ior.Right(x) => loop(Ior.both(a, x)) + } + } + loop(fn(b)) } - loop(fn(b)) + + override def pure[B](x: B): Ior[A, B] = Ior.right(x) + + def traverse[F[_]: Applicative, B, C](fa: A Ior B)(f: B => F[C]): F[A Ior C] = + fa.traverse(f) + + def foldLeft[B, C](fa: A Ior B, b: C)(f: (C, B) => C): C = + fa.foldLeft(b)(f) + + def foldRight[B, C](fa: A Ior B, lc: Eval[C])(f: (B, Eval[C]) => Eval[C]): Eval[C] = + fa.foldRight(lc)(f) + + override def map[B, C](fa: A Ior B)(f: B => C): A Ior C = + fa.map(f) + + override def forall[B](fa: Ior[A, B])(p: (B) => Boolean): Boolean = fa.forall(p) + + override def exists[B](fa: Ior[A, B])(p: (B) => Boolean): Boolean = fa.exists(p) } - } + // scalastyle:on method.length implicit def catsDataBifunctorForIor: Bifunctor[Ior] = new Bifunctor[Ior] { @@ -180,20 +211,6 @@ private[data] sealed abstract class IorInstances extends IorInstances0 { } } -private[data] sealed abstract class IorInstances0 { - - implicit def catsDataTraverseFunctorForIor[A]: Traverse[A Ior ?] with Functor[A Ior ?] = new Traverse[A Ior ?] with Functor[A Ior ?] { - def traverse[F[_]: Applicative, B, C](fa: A Ior B)(f: B => F[C]): F[A Ior C] = - fa.traverse(f) - def foldLeft[B, C](fa: A Ior B, b: C)(f: (C, B) => C): C = - fa.foldLeft(b)(f) - def foldRight[B, C](fa: A Ior B, lc: Eval[C])(f: (B, Eval[C]) => Eval[C]): Eval[C] = - fa.foldRight(lc)(f) - override def map[B, C](fa: A Ior B)(f: B => C): A Ior C = - fa.map(f) - } -} - private[data] sealed trait IorFunctions { def left[A, B](a: A): A Ior B = Ior.Left(a) def right[A, B](b: B): A Ior B = Ior.Right(b) From 564c4ecfef1378fccae650695e26618806b4fa3f Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sat, 18 Mar 2017 19:21:04 -0500 Subject: [PATCH 02/11] Revert "Added MonadError instance for Ior" This reverts commit 344e232522d77c4189b4c834f611a669489a813d. --- core/src/main/scala/cats/data/Ior.scala | 83 ++++++++++--------------- 1 file changed, 33 insertions(+), 50 deletions(-) diff --git a/core/src/main/scala/cats/data/Ior.scala b/core/src/main/scala/cats/data/Ior.scala index 0b80f5c839..8b79aa013a 100644 --- a/core/src/main/scala/cats/data/Ior.scala +++ b/core/src/main/scala/cats/data/Ior.scala @@ -140,7 +140,7 @@ object Ior extends IorInstances with IorFunctions { final case class Both[+A, +B](a: A, b: B) extends (A Ior B) } -private[data] sealed abstract class IorInstances { +private[data] sealed abstract class IorInstances extends IorInstances0 { implicit def catsDataEqForIor[A: Eq, B: Eq]: Eq[A Ior B] = new Eq[A Ior B] { def eqv(x: A Ior B, y: A Ior B): Boolean = x === y } @@ -153,57 +153,26 @@ private[data] sealed abstract class IorInstances { def combine(x: Ior[A, B], y: Ior[A, B]) = x.append(y) } - // scalastyle:off method.length - implicit def catsDataMonadErrorForIor[A: Semigroup]: MonadError[Ior[A, ?], A] with Traverse[Ior[A, ?]] = - new MonadError[Ior[A, ?], A] with Traverse[Ior[A, ?]] { - - def raiseError[B](e: A): Ior[A, B] = Ior.left(e) - - def handleErrorWith[B](fa: Ior[A, B])(f: (A) => Ior[A, B]): Ior[A, B] = - fa match { - case Ior.Left(e) => f(e) - case r @ Ior.Right(_) => r - case Ior.Both(e, _) => f(e) - } - - def flatMap[B, C](fa: Ior[A, B])(f: B => Ior[A, C]): Ior[A, C] = fa.flatMap(f) - - def tailRecM[B, C](b: B)(fn: B => Ior[A, Either[B, C]]): A Ior C = { - @tailrec - def loop(v: Ior[A, Either[B, C]]): A Ior C = v match { - case Ior.Left(a) => Ior.left(a) - case Ior.Right(Right(c)) => Ior.right(c) - case Ior.Both(a, Right(c)) => Ior.both(a, c) - case Ior.Right(Left(b)) => loop(fn(b)) - case Ior.Both(a, Left(b)) => - fn(b) match { - case Ior.Left(aa) => Ior.left(Semigroup[A].combine(a, aa)) - case Ior.Both(aa, x) => loop(Ior.both(Semigroup[A].combine(a, aa), x)) - case Ior.Right(x) => loop(Ior.both(a, x)) - } - } - loop(fn(b)) + implicit def catsDataMonadForIor[A: Semigroup]: Monad[A Ior ?] = new Monad[A Ior ?] { + def pure[B](b: B): A Ior B = Ior.right(b) + def flatMap[B, C](fa: A Ior B)(f: B => A Ior C): A Ior C = fa.flatMap(f) + def tailRecM[B, C](b: B)(fn: B => Ior[A, Either[B, C]]): A Ior C = { + @tailrec + def loop(v: Ior[A, Either[B, C]]): A Ior C = v match { + case Ior.Left(a) => Ior.left(a) + case Ior.Right(Right(c)) => Ior.right(c) + case Ior.Both(a, Right(c)) => Ior.both(a, c) + case Ior.Right(Left(b)) => loop(fn(b)) + case Ior.Both(a, Left(b)) => + fn(b) match { + case Ior.Left(aa) => Ior.left(Semigroup[A].combine(a, aa)) + case Ior.Both(aa, x) => loop(Ior.both(Semigroup[A].combine(a, aa), x)) + case Ior.Right(x) => loop(Ior.both(a, x)) + } } - - override def pure[B](x: B): Ior[A, B] = Ior.right(x) - - def traverse[F[_]: Applicative, B, C](fa: A Ior B)(f: B => F[C]): F[A Ior C] = - fa.traverse(f) - - def foldLeft[B, C](fa: A Ior B, b: C)(f: (C, B) => C): C = - fa.foldLeft(b)(f) - - def foldRight[B, C](fa: A Ior B, lc: Eval[C])(f: (B, Eval[C]) => Eval[C]): Eval[C] = - fa.foldRight(lc)(f) - - override def map[B, C](fa: A Ior B)(f: B => C): A Ior C = - fa.map(f) - - override def forall[B](fa: Ior[A, B])(p: (B) => Boolean): Boolean = fa.forall(p) - - override def exists[B](fa: Ior[A, B])(p: (B) => Boolean): Boolean = fa.exists(p) + loop(fn(b)) } - // scalastyle:on method.length + } implicit def catsDataBifunctorForIor: Bifunctor[Ior] = new Bifunctor[Ior] { @@ -211,6 +180,20 @@ private[data] sealed abstract class IorInstances { } } +private[data] sealed abstract class IorInstances0 { + + implicit def catsDataTraverseFunctorForIor[A]: Traverse[A Ior ?] with Functor[A Ior ?] = new Traverse[A Ior ?] with Functor[A Ior ?] { + def traverse[F[_]: Applicative, B, C](fa: A Ior B)(f: B => F[C]): F[A Ior C] = + fa.traverse(f) + def foldLeft[B, C](fa: A Ior B, b: C)(f: (C, B) => C): C = + fa.foldLeft(b)(f) + def foldRight[B, C](fa: A Ior B, lc: Eval[C])(f: (B, Eval[C]) => Eval[C]): Eval[C] = + fa.foldRight(lc)(f) + override def map[B, C](fa: A Ior B)(f: B => C): A Ior C = + fa.map(f) + } +} + private[data] sealed trait IorFunctions { def left[A, B](a: A): A Ior B = Ior.Left(a) def right[A, B](b: B): A Ior B = Ior.Right(b) From 0f77e851004c72ce4695d6509de058cb13631656 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sat, 18 Mar 2017 20:15:55 -0500 Subject: [PATCH 03/11] Added MonadError instance for Ior without mixing Traverse --- core/src/main/scala/cats/data/Ior.scala | 45 +++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/data/Ior.scala b/core/src/main/scala/cats/data/Ior.scala index 8b79aa013a..7a13f23229 100644 --- a/core/src/main/scala/cats/data/Ior.scala +++ b/core/src/main/scala/cats/data/Ior.scala @@ -1,7 +1,6 @@ package cats package data -import cats.functor.Bifunctor import scala.annotation.tailrec /** Represents a right-biased disjunction that is either an `A`, or a `B`, or both an `A` and a `B`. @@ -174,6 +173,43 @@ private[data] sealed abstract class IorInstances extends IorInstances0 { } } + implicit def catsDataMonadErrorForIor[A: Semigroup]: MonadError[Ior[A, ?], A] = + new MonadError[Ior[A, ?], A] { + + def raiseError[B](e: A): Ior[A, B] = Ior.left(e) + + def handleErrorWith[B](fa: Ior[A, B])(f: (A) => Ior[A, B]): Ior[A, B] = + fa match { + case Ior.Left(e) => f(e) + case r @ Ior.Right(_) => r + case Ior.Both(e, _) => f(e) + } + + def flatMap[B, C](fa: Ior[A, B])(f: B => Ior[A, C]): Ior[A, C] = fa.flatMap(f) + + def tailRecM[B, C](b: B)(fn: B => Ior[A, Either[B, C]]): A Ior C = { + @tailrec + def loop(v: Ior[A, Either[B, C]]): A Ior C = v match { + case Ior.Left(a) => Ior.left(a) + case Ior.Right(Right(c)) => Ior.right(c) + case Ior.Both(a, Right(c)) => Ior.both(a, c) + case Ior.Right(Left(b)) => loop(fn(b)) + case Ior.Both(a, Left(b)) => + fn(b) match { + case Ior.Left(aa) => Ior.left(Semigroup[A].combine(a, aa)) + case Ior.Both(aa, x) => loop(Ior.both(Semigroup[A].combine(a, aa), x)) + case Ior.Right(x) => loop(Ior.both(a, x)) + } + } + loop(fn(b)) + } + + override def pure[B](x: B): Ior[A, B] = Ior.right(x) + + override def map[B, C](fa: A Ior B)(f: B => C): A Ior C = + fa.map(f) + } + implicit def catsDataBifunctorForIor: Bifunctor[Ior] = new Bifunctor[Ior] { override def bimap[A, B, C, D](fab: A Ior B)(f: A => C, g: B => D): C Ior D = fab.bimap(f, g) @@ -182,13 +218,18 @@ private[data] sealed abstract class IorInstances extends IorInstances0 { private[data] sealed abstract class IorInstances0 { - implicit def catsDataTraverseFunctorForIor[A]: Traverse[A Ior ?] with Functor[A Ior ?] = new Traverse[A Ior ?] with Functor[A Ior ?] { + implicit def catsDataTraverseFunctorForIor[A]: Traverse[A Ior ?] = new Traverse[A Ior ?] { def traverse[F[_]: Applicative, B, C](fa: A Ior B)(f: B => F[C]): F[A Ior C] = fa.traverse(f) def foldLeft[B, C](fa: A Ior B, b: C)(f: (C, B) => C): C = fa.foldLeft(b)(f) def foldRight[B, C](fa: A Ior B, lc: Eval[C])(f: (B, Eval[C]) => Eval[C]): Eval[C] = fa.foldRight(lc)(f) + + override def forall[B](fa: Ior[A, B])(p: (B) => Boolean): Boolean = fa.forall(p) + + override def exists[B](fa: Ior[A, B])(p: (B) => Boolean): Boolean = fa.exists(p) + override def map[B, C](fa: A Ior B)(f: B => C): A Ior C = fa.map(f) } From b72d741a1e292e1b70b17d2053ce4a14bdf3a624 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sat, 18 Mar 2017 20:34:42 -0500 Subject: [PATCH 04/11] Removed Monad instance --- core/src/main/scala/cats/data/Ior.scala | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/core/src/main/scala/cats/data/Ior.scala b/core/src/main/scala/cats/data/Ior.scala index 7a13f23229..3ec00f2c1c 100644 --- a/core/src/main/scala/cats/data/Ior.scala +++ b/core/src/main/scala/cats/data/Ior.scala @@ -1,6 +1,8 @@ package cats package data +import cats.functor.Bifunctor + import scala.annotation.tailrec /** Represents a right-biased disjunction that is either an `A`, or a `B`, or both an `A` and a `B`. @@ -152,27 +154,6 @@ private[data] sealed abstract class IorInstances extends IorInstances0 { def combine(x: Ior[A, B], y: Ior[A, B]) = x.append(y) } - implicit def catsDataMonadForIor[A: Semigroup]: Monad[A Ior ?] = new Monad[A Ior ?] { - def pure[B](b: B): A Ior B = Ior.right(b) - def flatMap[B, C](fa: A Ior B)(f: B => A Ior C): A Ior C = fa.flatMap(f) - def tailRecM[B, C](b: B)(fn: B => Ior[A, Either[B, C]]): A Ior C = { - @tailrec - def loop(v: Ior[A, Either[B, C]]): A Ior C = v match { - case Ior.Left(a) => Ior.left(a) - case Ior.Right(Right(c)) => Ior.right(c) - case Ior.Both(a, Right(c)) => Ior.both(a, c) - case Ior.Right(Left(b)) => loop(fn(b)) - case Ior.Both(a, Left(b)) => - fn(b) match { - case Ior.Left(aa) => Ior.left(Semigroup[A].combine(a, aa)) - case Ior.Both(aa, x) => loop(Ior.both(Semigroup[A].combine(a, aa), x)) - case Ior.Right(x) => loop(Ior.both(a, x)) - } - } - loop(fn(b)) - } - } - implicit def catsDataMonadErrorForIor[A: Semigroup]: MonadError[Ior[A, ?], A] = new MonadError[Ior[A, ?], A] { From 43077d5fa545e57628409f3da0a30f0ceb7270a3 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sat, 18 Mar 2017 20:35:02 -0500 Subject: [PATCH 05/11] Added MonadError tests to Ior --- tests/src/test/scala/cats/tests/IorTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/test/scala/cats/tests/IorTests.scala b/tests/src/test/scala/cats/tests/IorTests.scala index ae8e4946af..155d98d403 100644 --- a/tests/src/test/scala/cats/tests/IorTests.scala +++ b/tests/src/test/scala/cats/tests/IorTests.scala @@ -15,7 +15,7 @@ class IorTests extends CatsSuite { checkAll("Cartesian[String Ior ?]]", SerializableTests.serializable(Cartesian[String Ior ?])) checkAll("Ior[String, Int]", MonadTests[String Ior ?].monad[Int, Int, Int]) - checkAll("Monad[String Ior ?]]", SerializableTests.serializable(Monad[String Ior ?])) + checkAll("MonadError[String Ior ?]", SerializableTests.serializable(MonadError[String Ior ?, String])) checkAll("Ior[String, Int] with Option", TraverseTests[String Ior ?].traverse[Int, Int, Int, Int, Option, Option]) checkAll("Traverse[String Ior ?]", SerializableTests.serializable(Traverse[String Ior ?])) From 213452ab69c82d6d66c543aff964af0b8741af5f Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sat, 18 Mar 2017 21:32:59 -0500 Subject: [PATCH 06/11] Added MonadErrorTests for Ior --- core/src/main/scala/cats/data/Validated.scala | 73 +++++++++++-------- .../src/test/scala/cats/tests/IorTests.scala | 8 +- 2 files changed, 46 insertions(+), 35 deletions(-) diff --git a/core/src/main/scala/cats/data/Validated.scala b/core/src/main/scala/cats/data/Validated.scala index 7d65e570ec..24f2b30d18 100644 --- a/core/src/main/scala/cats/data/Validated.scala +++ b/core/src/main/scala/cats/data/Validated.scala @@ -295,16 +295,8 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance } // scalastyle:off method.length - implicit def catsDataInstancesForValidated[E](implicit E: Semigroup[E]): Traverse[Validated[E, ?]] with ApplicativeError[Validated[E, ?], E] = - new Traverse[Validated[E, ?]] with ApplicativeError[Validated[E, ?], E] { - def traverse[F[_]: Applicative, A, B](fa: Validated[E, A])(f: A => F[B]): F[Validated[E, B]] = - fa.traverse(f) - - def foldLeft[A, B](fa: Validated[E, A], b: B)(f: (B, A) => B): B = - fa.foldLeft(b)(f) - - def foldRight[A, B](fa: Validated[E, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = - fa.foldRight(lb)(f) + implicit def catsDataApplicativeErrorForValidated[E](implicit E: Semigroup[E]): ApplicativeError[Validated[E, ?], E] = + new ApplicativeError[Validated[E, ?], E] { def pure[A](a: A): Validated[E, A] = Validated.valid(a) @@ -324,6 +316,45 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance case v @ Validated.Valid(_) => v } def raiseError[A](e: E): Validated[E, A] = Validated.Invalid(e) + } + // scalastyle:on method.length +} + +private[data] sealed abstract class ValidatedInstances1 extends ValidatedInstances2 { + + implicit def catsDataSemigroupForValidated[A, B](implicit A: Semigroup[A], B: Semigroup[B]): Semigroup[Validated[A, B]] = + new Semigroup[Validated[A, B]] { + def combine(x: Validated[A, B], y: Validated[A, B]): Validated[A, B] = x combine y + } + + implicit def catsDataPartialOrderForValidated[A: PartialOrder, B: PartialOrder]: PartialOrder[Validated[A, B]] = + new PartialOrder[Validated[A, B]] { + def partialCompare(x: Validated[A, B], y: Validated[A, B]): Double = x partialCompare y + override def eqv(x: Validated[A, B], y: Validated[A, B]): Boolean = x === y + } +} + +private[data] sealed abstract class ValidatedInstances2 { + implicit def catsDataEqForValidated[A: Eq, B: Eq]: Eq[Validated[A, B]] = + new Eq[Validated[A, B]] { + def eqv(x: Validated[A, B], y: Validated[A, B]): Boolean = x === y + } + + // scalastyle:off method.length + implicit def catsDataTraverseFunctorForValidated[E]: Traverse[Validated[E, ?]] = + new Traverse[Validated[E, ?]] { + + override def traverse[G[_] : Applicative, A, B](fa: Validated[E, A])(f: (A) => G[B]): G[Validated[E, B]] = + fa.traverse(f) + + override def foldLeft[A, B](fa: Validated[E, A], b: B)(f: (B, A) => B): B = + fa.foldLeft(b)(f) + + override def foldRight[A, B](fa: Validated[E, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + fa.foldRight(lb)(f) + + override def map[A, B](fa: Validated[E, A])(f: (A) => B): Validated[E, B] = + fa.map(f) override def reduceLeftToOption[A, B](fa: Validated[E, A])(f: A => B)(g: (B, A) => B): Option[B] = fa.map(f).toOption @@ -357,28 +388,6 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance override def isEmpty[A](fa: Validated[E, A]): Boolean = fa.isInvalid } - // scalastyle:on method.length -} - -private[data] sealed abstract class ValidatedInstances1 extends ValidatedInstances2 { - - implicit def catsDataSemigroupForValidated[A, B](implicit A: Semigroup[A], B: Semigroup[B]): Semigroup[Validated[A, B]] = - new Semigroup[Validated[A, B]] { - def combine(x: Validated[A, B], y: Validated[A, B]): Validated[A, B] = x combine y - } - - implicit def catsDataPartialOrderForValidated[A: PartialOrder, B: PartialOrder]: PartialOrder[Validated[A, B]] = - new PartialOrder[Validated[A, B]] { - def partialCompare(x: Validated[A, B], y: Validated[A, B]): Double = x partialCompare y - override def eqv(x: Validated[A, B], y: Validated[A, B]): Boolean = x === y - } -} - -private[data] sealed abstract class ValidatedInstances2 { - implicit def catsDataEqForValidated[A: Eq, B: Eq]: Eq[Validated[A, B]] = - new Eq[Validated[A, B]] { - def eqv(x: Validated[A, B], y: Validated[A, B]): Boolean = x === y - } } private[data] trait ValidatedFunctions { diff --git a/tests/src/test/scala/cats/tests/IorTests.scala b/tests/src/test/scala/cats/tests/IorTests.scala index 155d98d403..e15e23ba71 100644 --- a/tests/src/test/scala/cats/tests/IorTests.scala +++ b/tests/src/test/scala/cats/tests/IorTests.scala @@ -1,9 +1,9 @@ package cats package tests -import cats.data.Ior +import cats.data.{EitherT, Ior} import cats.kernel.laws.GroupLaws -import cats.laws.discipline.{BifunctorTests, CartesianTests, MonadTests, SerializableTests, TraverseTests} +import cats.laws.discipline.{BifunctorTests, CartesianTests, MonadErrorTests, SerializableTests, TraverseTests} import cats.laws.discipline.arbitrary._ import org.scalacheck.Arbitrary._ @@ -14,7 +14,9 @@ class IorTests extends CatsSuite { checkAll("Ior[String, Int]", CartesianTests[Ior[String, ?]].cartesian[Int, Int, Int]) checkAll("Cartesian[String Ior ?]]", SerializableTests.serializable(Cartesian[String Ior ?])) - checkAll("Ior[String, Int]", MonadTests[String Ior ?].monad[Int, Int, Int]) + implicit val eq0 = EitherT.catsDataEqForEitherT[Ior[String, ?], String, Int] + + checkAll("Ior[String, Int]", MonadErrorTests[String Ior ?, String].monadError[Int, Int, Int]) checkAll("MonadError[String Ior ?]", SerializableTests.serializable(MonadError[String Ior ?, String])) checkAll("Ior[String, Int] with Option", TraverseTests[String Ior ?].traverse[Int, Int, Int, Int, Option, Option]) From ededf7a0eceda79079a406482f4491451e57eb84 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sat, 18 Mar 2017 21:34:14 -0500 Subject: [PATCH 07/11] Revert "Added MonadErrorTests for Ior" This reverts commit 213452ab69c82d6d66c543aff964af0b8741af5f. --- core/src/main/scala/cats/data/Validated.scala | 73 ++++++++----------- .../src/test/scala/cats/tests/IorTests.scala | 8 +- 2 files changed, 35 insertions(+), 46 deletions(-) diff --git a/core/src/main/scala/cats/data/Validated.scala b/core/src/main/scala/cats/data/Validated.scala index 24f2b30d18..7d65e570ec 100644 --- a/core/src/main/scala/cats/data/Validated.scala +++ b/core/src/main/scala/cats/data/Validated.scala @@ -295,8 +295,16 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance } // scalastyle:off method.length - implicit def catsDataApplicativeErrorForValidated[E](implicit E: Semigroup[E]): ApplicativeError[Validated[E, ?], E] = - new ApplicativeError[Validated[E, ?], E] { + implicit def catsDataInstancesForValidated[E](implicit E: Semigroup[E]): Traverse[Validated[E, ?]] with ApplicativeError[Validated[E, ?], E] = + new Traverse[Validated[E, ?]] with ApplicativeError[Validated[E, ?], E] { + def traverse[F[_]: Applicative, A, B](fa: Validated[E, A])(f: A => F[B]): F[Validated[E, B]] = + fa.traverse(f) + + def foldLeft[A, B](fa: Validated[E, A], b: B)(f: (B, A) => B): B = + fa.foldLeft(b)(f) + + def foldRight[A, B](fa: Validated[E, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + fa.foldRight(lb)(f) def pure[A](a: A): Validated[E, A] = Validated.valid(a) @@ -316,45 +324,6 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance case v @ Validated.Valid(_) => v } def raiseError[A](e: E): Validated[E, A] = Validated.Invalid(e) - } - // scalastyle:on method.length -} - -private[data] sealed abstract class ValidatedInstances1 extends ValidatedInstances2 { - - implicit def catsDataSemigroupForValidated[A, B](implicit A: Semigroup[A], B: Semigroup[B]): Semigroup[Validated[A, B]] = - new Semigroup[Validated[A, B]] { - def combine(x: Validated[A, B], y: Validated[A, B]): Validated[A, B] = x combine y - } - - implicit def catsDataPartialOrderForValidated[A: PartialOrder, B: PartialOrder]: PartialOrder[Validated[A, B]] = - new PartialOrder[Validated[A, B]] { - def partialCompare(x: Validated[A, B], y: Validated[A, B]): Double = x partialCompare y - override def eqv(x: Validated[A, B], y: Validated[A, B]): Boolean = x === y - } -} - -private[data] sealed abstract class ValidatedInstances2 { - implicit def catsDataEqForValidated[A: Eq, B: Eq]: Eq[Validated[A, B]] = - new Eq[Validated[A, B]] { - def eqv(x: Validated[A, B], y: Validated[A, B]): Boolean = x === y - } - - // scalastyle:off method.length - implicit def catsDataTraverseFunctorForValidated[E]: Traverse[Validated[E, ?]] = - new Traverse[Validated[E, ?]] { - - override def traverse[G[_] : Applicative, A, B](fa: Validated[E, A])(f: (A) => G[B]): G[Validated[E, B]] = - fa.traverse(f) - - override def foldLeft[A, B](fa: Validated[E, A], b: B)(f: (B, A) => B): B = - fa.foldLeft(b)(f) - - override def foldRight[A, B](fa: Validated[E, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = - fa.foldRight(lb)(f) - - override def map[A, B](fa: Validated[E, A])(f: (A) => B): Validated[E, B] = - fa.map(f) override def reduceLeftToOption[A, B](fa: Validated[E, A])(f: A => B)(g: (B, A) => B): Option[B] = fa.map(f).toOption @@ -388,6 +357,28 @@ private[data] sealed abstract class ValidatedInstances2 { override def isEmpty[A](fa: Validated[E, A]): Boolean = fa.isInvalid } + // scalastyle:on method.length +} + +private[data] sealed abstract class ValidatedInstances1 extends ValidatedInstances2 { + + implicit def catsDataSemigroupForValidated[A, B](implicit A: Semigroup[A], B: Semigroup[B]): Semigroup[Validated[A, B]] = + new Semigroup[Validated[A, B]] { + def combine(x: Validated[A, B], y: Validated[A, B]): Validated[A, B] = x combine y + } + + implicit def catsDataPartialOrderForValidated[A: PartialOrder, B: PartialOrder]: PartialOrder[Validated[A, B]] = + new PartialOrder[Validated[A, B]] { + def partialCompare(x: Validated[A, B], y: Validated[A, B]): Double = x partialCompare y + override def eqv(x: Validated[A, B], y: Validated[A, B]): Boolean = x === y + } +} + +private[data] sealed abstract class ValidatedInstances2 { + implicit def catsDataEqForValidated[A: Eq, B: Eq]: Eq[Validated[A, B]] = + new Eq[Validated[A, B]] { + def eqv(x: Validated[A, B], y: Validated[A, B]): Boolean = x === y + } } private[data] trait ValidatedFunctions { diff --git a/tests/src/test/scala/cats/tests/IorTests.scala b/tests/src/test/scala/cats/tests/IorTests.scala index e15e23ba71..155d98d403 100644 --- a/tests/src/test/scala/cats/tests/IorTests.scala +++ b/tests/src/test/scala/cats/tests/IorTests.scala @@ -1,9 +1,9 @@ package cats package tests -import cats.data.{EitherT, Ior} +import cats.data.Ior import cats.kernel.laws.GroupLaws -import cats.laws.discipline.{BifunctorTests, CartesianTests, MonadErrorTests, SerializableTests, TraverseTests} +import cats.laws.discipline.{BifunctorTests, CartesianTests, MonadTests, SerializableTests, TraverseTests} import cats.laws.discipline.arbitrary._ import org.scalacheck.Arbitrary._ @@ -14,9 +14,7 @@ class IorTests extends CatsSuite { checkAll("Ior[String, Int]", CartesianTests[Ior[String, ?]].cartesian[Int, Int, Int]) checkAll("Cartesian[String Ior ?]]", SerializableTests.serializable(Cartesian[String Ior ?])) - implicit val eq0 = EitherT.catsDataEqForEitherT[Ior[String, ?], String, Int] - - checkAll("Ior[String, Int]", MonadErrorTests[String Ior ?, String].monadError[Int, Int, Int]) + checkAll("Ior[String, Int]", MonadTests[String Ior ?].monad[Int, Int, Int]) checkAll("MonadError[String Ior ?]", SerializableTests.serializable(MonadError[String Ior ?, String])) checkAll("Ior[String, Int] with Option", TraverseTests[String Ior ?].traverse[Int, Int, Int, Int, Option, Option]) From 6c5807073384382e713d9062aaeade70b7f81c78 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sat, 18 Mar 2017 21:35:58 -0500 Subject: [PATCH 08/11] Separated Traverse instance from ApplicativeError instance for Validated --- core/src/main/scala/cats/data/Validated.scala | 73 +++++++++++-------- .../src/test/scala/cats/tests/IorTests.scala | 8 +- 2 files changed, 46 insertions(+), 35 deletions(-) diff --git a/core/src/main/scala/cats/data/Validated.scala b/core/src/main/scala/cats/data/Validated.scala index 7d65e570ec..24f2b30d18 100644 --- a/core/src/main/scala/cats/data/Validated.scala +++ b/core/src/main/scala/cats/data/Validated.scala @@ -295,16 +295,8 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance } // scalastyle:off method.length - implicit def catsDataInstancesForValidated[E](implicit E: Semigroup[E]): Traverse[Validated[E, ?]] with ApplicativeError[Validated[E, ?], E] = - new Traverse[Validated[E, ?]] with ApplicativeError[Validated[E, ?], E] { - def traverse[F[_]: Applicative, A, B](fa: Validated[E, A])(f: A => F[B]): F[Validated[E, B]] = - fa.traverse(f) - - def foldLeft[A, B](fa: Validated[E, A], b: B)(f: (B, A) => B): B = - fa.foldLeft(b)(f) - - def foldRight[A, B](fa: Validated[E, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = - fa.foldRight(lb)(f) + implicit def catsDataApplicativeErrorForValidated[E](implicit E: Semigroup[E]): ApplicativeError[Validated[E, ?], E] = + new ApplicativeError[Validated[E, ?], E] { def pure[A](a: A): Validated[E, A] = Validated.valid(a) @@ -324,6 +316,45 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance case v @ Validated.Valid(_) => v } def raiseError[A](e: E): Validated[E, A] = Validated.Invalid(e) + } + // scalastyle:on method.length +} + +private[data] sealed abstract class ValidatedInstances1 extends ValidatedInstances2 { + + implicit def catsDataSemigroupForValidated[A, B](implicit A: Semigroup[A], B: Semigroup[B]): Semigroup[Validated[A, B]] = + new Semigroup[Validated[A, B]] { + def combine(x: Validated[A, B], y: Validated[A, B]): Validated[A, B] = x combine y + } + + implicit def catsDataPartialOrderForValidated[A: PartialOrder, B: PartialOrder]: PartialOrder[Validated[A, B]] = + new PartialOrder[Validated[A, B]] { + def partialCompare(x: Validated[A, B], y: Validated[A, B]): Double = x partialCompare y + override def eqv(x: Validated[A, B], y: Validated[A, B]): Boolean = x === y + } +} + +private[data] sealed abstract class ValidatedInstances2 { + implicit def catsDataEqForValidated[A: Eq, B: Eq]: Eq[Validated[A, B]] = + new Eq[Validated[A, B]] { + def eqv(x: Validated[A, B], y: Validated[A, B]): Boolean = x === y + } + + // scalastyle:off method.length + implicit def catsDataTraverseFunctorForValidated[E]: Traverse[Validated[E, ?]] = + new Traverse[Validated[E, ?]] { + + override def traverse[G[_] : Applicative, A, B](fa: Validated[E, A])(f: (A) => G[B]): G[Validated[E, B]] = + fa.traverse(f) + + override def foldLeft[A, B](fa: Validated[E, A], b: B)(f: (B, A) => B): B = + fa.foldLeft(b)(f) + + override def foldRight[A, B](fa: Validated[E, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + fa.foldRight(lb)(f) + + override def map[A, B](fa: Validated[E, A])(f: (A) => B): Validated[E, B] = + fa.map(f) override def reduceLeftToOption[A, B](fa: Validated[E, A])(f: A => B)(g: (B, A) => B): Option[B] = fa.map(f).toOption @@ -357,28 +388,6 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance override def isEmpty[A](fa: Validated[E, A]): Boolean = fa.isInvalid } - // scalastyle:on method.length -} - -private[data] sealed abstract class ValidatedInstances1 extends ValidatedInstances2 { - - implicit def catsDataSemigroupForValidated[A, B](implicit A: Semigroup[A], B: Semigroup[B]): Semigroup[Validated[A, B]] = - new Semigroup[Validated[A, B]] { - def combine(x: Validated[A, B], y: Validated[A, B]): Validated[A, B] = x combine y - } - - implicit def catsDataPartialOrderForValidated[A: PartialOrder, B: PartialOrder]: PartialOrder[Validated[A, B]] = - new PartialOrder[Validated[A, B]] { - def partialCompare(x: Validated[A, B], y: Validated[A, B]): Double = x partialCompare y - override def eqv(x: Validated[A, B], y: Validated[A, B]): Boolean = x === y - } -} - -private[data] sealed abstract class ValidatedInstances2 { - implicit def catsDataEqForValidated[A: Eq, B: Eq]: Eq[Validated[A, B]] = - new Eq[Validated[A, B]] { - def eqv(x: Validated[A, B], y: Validated[A, B]): Boolean = x === y - } } private[data] trait ValidatedFunctions { diff --git a/tests/src/test/scala/cats/tests/IorTests.scala b/tests/src/test/scala/cats/tests/IorTests.scala index 155d98d403..e15e23ba71 100644 --- a/tests/src/test/scala/cats/tests/IorTests.scala +++ b/tests/src/test/scala/cats/tests/IorTests.scala @@ -1,9 +1,9 @@ package cats package tests -import cats.data.Ior +import cats.data.{EitherT, Ior} import cats.kernel.laws.GroupLaws -import cats.laws.discipline.{BifunctorTests, CartesianTests, MonadTests, SerializableTests, TraverseTests} +import cats.laws.discipline.{BifunctorTests, CartesianTests, MonadErrorTests, SerializableTests, TraverseTests} import cats.laws.discipline.arbitrary._ import org.scalacheck.Arbitrary._ @@ -14,7 +14,9 @@ class IorTests extends CatsSuite { checkAll("Ior[String, Int]", CartesianTests[Ior[String, ?]].cartesian[Int, Int, Int]) checkAll("Cartesian[String Ior ?]]", SerializableTests.serializable(Cartesian[String Ior ?])) - checkAll("Ior[String, Int]", MonadTests[String Ior ?].monad[Int, Int, Int]) + implicit val eq0 = EitherT.catsDataEqForEitherT[Ior[String, ?], String, Int] + + checkAll("Ior[String, Int]", MonadErrorTests[String Ior ?, String].monadError[Int, Int, Int]) checkAll("MonadError[String Ior ?]", SerializableTests.serializable(MonadError[String Ior ?, String])) checkAll("Ior[String, Int] with Option", TraverseTests[String Ior ?].traverse[Int, Int, Int, Int, Option, Option]) From a48b04ca17cd12ed012a46cc7226ead8299d7b0e Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sun, 19 Mar 2017 19:57:28 -0500 Subject: [PATCH 09/11] Added test for ior valueOr --- tests/src/test/scala/cats/tests/IorTests.scala | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/src/test/scala/cats/tests/IorTests.scala b/tests/src/test/scala/cats/tests/IorTests.scala index e15e23ba71..32dc50cccb 100644 --- a/tests/src/test/scala/cats/tests/IorTests.scala +++ b/tests/src/test/scala/cats/tests/IorTests.scala @@ -65,6 +65,12 @@ class IorTests extends CatsSuite { } } + test("valueOr consistent with leftMap") { + forAll { (i: Int Ior String, f: Int => String) => + i.valueOr(f) should === (i.leftMap(f).fold(identity, identity, _ + _)) + } + } + test("isLeft consistent with toOption") { forAll { (i: Int Ior String) => i.isLeft should === (i.toOption.isEmpty) From b2d3e469a824c4c44efb1cfee2f66c302bc909fd Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Thu, 6 Apr 2017 20:19:33 -0500 Subject: [PATCH 10/11] Fixed some slastyle comments --- core/src/main/scala/cats/data/Validated.scala | 3 +-- tests/src/test/scala/cats/tests/IorTests.scala | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/core/src/main/scala/cats/data/Validated.scala b/core/src/main/scala/cats/data/Validated.scala index e3909a2505..026434641a 100644 --- a/core/src/main/scala/cats/data/Validated.scala +++ b/core/src/main/scala/cats/data/Validated.scala @@ -299,7 +299,6 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance fab.leftMap(f) } - // scalastyle:off method.length implicit def catsDataApplicativeErrorForValidated[E](implicit E: Semigroup[E]): ApplicativeError[Validated[E, ?], E] = new ApplicativeError[Validated[E, ?], E] { @@ -322,7 +321,6 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance } def raiseError[A](e: E): Validated[E, A] = Validated.Invalid(e) } - // scalastyle:on method.length } private[data] sealed abstract class ValidatedInstances1 extends ValidatedInstances2 { @@ -393,6 +391,7 @@ private[data] sealed abstract class ValidatedInstances2 { override def isEmpty[A](fa: Validated[E, A]): Boolean = fa.isInvalid } + // scalastyle:off method.length } private[data] trait ValidatedFunctions { diff --git a/tests/src/test/scala/cats/tests/IorTests.scala b/tests/src/test/scala/cats/tests/IorTests.scala index 954c92f02f..78589c3753 100644 --- a/tests/src/test/scala/cats/tests/IorTests.scala +++ b/tests/src/test/scala/cats/tests/IorTests.scala @@ -6,7 +6,6 @@ import cats.laws.discipline.{BifunctorTests, CartesianTests, MonadErrorTests, Se import cats.data.{Ior, NonEmptyList, EitherT} import cats.kernel.laws.GroupLaws import cats.laws.discipline.arbitrary._ -import cats.laws.discipline.{BifunctorTests, CartesianTests, MonadTests, SerializableTests, TraverseTests} import org.scalacheck.Arbitrary._ class IorTests extends CatsSuite { From d23e374781a0501e15fcb2b4c7afd42207ba0066 Mon Sep 17 00:00:00 2001 From: Leandro Bolivar Date: Sat, 8 Apr 2017 09:58:19 -0500 Subject: [PATCH 11/11] Deleted duplicated import --- tests/src/test/scala/cats/tests/IorTests.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/src/test/scala/cats/tests/IorTests.scala b/tests/src/test/scala/cats/tests/IorTests.scala index 78589c3753..89cb8cc0ea 100644 --- a/tests/src/test/scala/cats/tests/IorTests.scala +++ b/tests/src/test/scala/cats/tests/IorTests.scala @@ -4,7 +4,6 @@ package tests import cats.kernel.laws.GroupLaws import cats.laws.discipline.{BifunctorTests, CartesianTests, MonadErrorTests, SerializableTests, TraverseTests} import cats.data.{Ior, NonEmptyList, EitherT} -import cats.kernel.laws.GroupLaws import cats.laws.discipline.arbitrary._ import org.scalacheck.Arbitrary._