From 289c2fb60cb5e76c38cf2226f8639615b4d24dc7 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 5 Nov 2018 14:58:12 -0800 Subject: [PATCH 01/87] Add Decideable --- core/src/main/scala/cats/Decideable.scala | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 core/src/main/scala/cats/Decideable.scala diff --git a/core/src/main/scala/cats/Decideable.scala b/core/src/main/scala/cats/Decideable.scala new file mode 100644 index 0000000000..9d75bcc3e2 --- /dev/null +++ b/core/src/main/scala/cats/Decideable.scala @@ -0,0 +1,27 @@ +package cats + +import simulacrum.typeclass + +/** + * [[Decideable]] functors are functors that supply + * a `decide` operation allowing choices to be made. + * + * This is comparable to [[Alternative]] in the + * covariant case. + * + * Must obey laws in cats.laws.DecideableLaws. + * + * Based on ekmett's contravariant library: + * https://hackage.haskell.org/package/contravariant-1.4/docs/Data-Functor-Contravariant-Divisible.html#g:2 + */ +@typeclass trait Decideable[F[_]] extends ContravariantMonoidal[F] { + def sum[A, B](fa: F[A], fb: F[B]): F[Either[A, B]] + + def decide[A, B, C](fa: F[A], fb: F[B])(f: C => Either[A, B]): F[C] = + contramap(sum(fa, fb))(f) + + def chosen[B, C](fb: F[B], fc: F[C]): F[Either[B, C]] = + decide(fb, fc)(identity[Either[B, C]]) + + def zero: F[Nothing] = trivial[Nothing] +} From ab2105fa48487528b32f73b625ffd260405f30f3 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 5 Nov 2018 14:58:24 -0800 Subject: [PATCH 02/87] Add first batch of instances --- core/src/main/scala/cats/data/Op.scala | 25 ++++++++++++++++++ core/src/main/scala/cats/data/OptionT.scala | 15 +++++++++++ core/src/main/scala/cats/data/WriterT.scala | 19 ++++++++++++++ core/src/main/scala/cats/instances/eq.scala | 19 ++++++++++++-- .../src/main/scala/cats/instances/equiv.scala | 20 ++++++++++++-- .../main/scala/cats/instances/function.scala | 26 ++++++++++++++----- .../src/main/scala/cats/instances/order.scala | 20 ++++++++++++-- 7 files changed, 132 insertions(+), 12 deletions(-) diff --git a/core/src/main/scala/cats/data/Op.scala b/core/src/main/scala/cats/data/Op.scala index 39a4bf234f..025d8623d4 100644 --- a/core/src/main/scala/cats/data/Op.scala +++ b/core/src/main/scala/cats/data/Op.scala @@ -20,6 +20,12 @@ sealed abstract private[data] class OpInstances extends OpInstances0 { implicit def catsDataCategoryForOp[Arr[_, _]](implicit ArrC: Category[Arr]): Category[Op[Arr, ?, ?]] = new OpCategory[Arr] { def Arr: Category[Arr] = ArrC } + implicit def catsDataDecideableForOp[Arr[_, _], R](implicit ArrC: ArrowChoice[Arr], monn: Monoid[R]): Decideable[Op[Arr, R, ?]] = + new OpDecideable[Arr, R] { + def Arr: ArrowChoice[Arr] = ArrC + def M: Monoid[R] = monn + } + implicit def catsKernelEqForOp[Arr[_, _], A, B](implicit ArrEq: Eq[Arr[B, A]]): Eq[Op[Arr, A, B]] = new OpEq[Arr, A, B] { def Arr: Eq[Arr[B, A]] = ArrEq } } @@ -42,6 +48,25 @@ private[data] trait OpCompose[Arr[_, _]] extends Compose[Op[Arr, ?, ?]] { f.compose(g) } +private[data] trait OpDecideable[Arr[_, _], R] extends Decideable[Op[Arr, R, ?]] { + implicit def Arr: ArrowChoice[Arr] + implicit def M: Monoid[R] + + def unit: Op[Arr, R, Unit] = + Op(Arr.lift(Function.const(M.empty))) + + def contramap[A, B](fa: Op[Arr, R, A])(f: B => A): Op[Arr, R, B] = + Op(Arr.compose(fa.run, Arr.lift(f))) + + def product[A, B](fa: Op[Arr, R, A], fb: Op[Arr, R, B]): Op[Arr, R, (A, B)] = + Op(Arr.compose( + Arr.lift((M.combine _).tupled), + Arr.split(fa.run, fb.run))) + + def sum[A, B](fa: Op[Arr, R, A], fb: Op[Arr, R, B]): Op[Arr, R, Either[A, B]] = + Op(Arr.choice(fa.run, fb.run)) +} + private[data] trait OpEq[Arr[_, _], A, B] extends Eq[Op[Arr, A, B]] { implicit def Arr: Eq[Arr[B, A]] diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index 1b5b19c84d..528f815c5d 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -267,6 +267,9 @@ sealed abstract private[data] class OptionTInstances extends OptionTInstances0 { G.map(Traverse[F].traverse(fa.value)(TraverseFilter[Option].filterA[G, A](_)(f)))(OptionT[F, A]) } + + implicit def catsDataDecideableForOptionT[F[_]](implicit F0: Decideable[F]): Decideable[OptionT[F, ?]] = + new OptionTDecideable[F] { implicit val F = F0 } } sealed abstract private[data] class OptionTInstances0 extends OptionTInstances1 { @@ -382,6 +385,18 @@ private trait OptionTMonadError[F[_], E] extends MonadError[OptionT[F, ?], E] wi OptionT(F.handleErrorWith(fa.value)(f(_).value)) } +private trait OptionTDecideable[F[_]] extends Decideable[OptionT[F, ?]] with OptionTContravariantMonoidal[F] { + def F: Decideable[F] + + def sum[A, B](fa: OptionT[F, A], fb: OptionT[F, B]): OptionT[F, Either[A, B]] = + OptionT(F.decide(fa.value, fb.value)( + (e: Option[Either[A, B]]) => e match { + case Some(Right(b)) => Right(Option(b)) + case Some(Left(a)) => Left(Option(a)) + case None => Left(None) + })) +} + private trait OptionTContravariantMonoidal[F[_]] extends ContravariantMonoidal[OptionT[F, ?]] { def F: ContravariantMonoidal[F] diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index 4b15308aae..b319edf804 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -241,6 +241,13 @@ sealed abstract private[data] class WriterTInstances6 extends WriterTInstances7 implicit val F0: ApplicativeError[F, E] = F implicit val L0: Monoid[L] = L } + + implicit def catsDataDecideableForWriterT[F[_], L]( + implicit F: Decideable[F] + ): Decideable[WriterT[F, L, ?]] = + new WriterTDecideable[F, L] { + implicit val F0: Decideable[F] = F + } } sealed abstract private[data] class WriterTInstances7 extends WriterTInstances8 { @@ -462,6 +469,18 @@ sealed private[data] trait WriterTAlternative[F[_], L] implicit override def F0: Alternative[F] } +sealed private[data] trait WriterTDecideable[F[_], L] extends WriterTContravariantMonoidal[F, L] with Decideable[WriterT[F, L, ?]] { + implicit def F0: Decideable[F] + + override def sum[A, B](fa: WriterT[F, L, A], fb: WriterT[F, L, B]): WriterT[F, L, Either[A, B]] = + WriterT(F0.decide(fa.run, fb.run)( + (e: (L, Either[A, B])) => + e match { + case (l, Right(b)) => Right((l, b)) + case (l, Left(a)) => Left((l, a)) + })) +} + sealed private[data] trait WriterTContravariantMonoidal[F[_], L] extends ContravariantMonoidal[WriterT[F, L, ?]] { implicit def F0: ContravariantMonoidal[F] diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index 5140bca36f..ac9983fece 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -1,9 +1,12 @@ package cats package instances +import cats.instances.either._ +import cats.syntax.apply._ + trait EqInstances extends kernel.instances.EqInstances { - implicit val catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = - new ContravariantMonoidal[Eq] { + implicit val catsDecideableForEq: Decideable[Eq] = + new Decideable[Eq] { /** * Defaults to the trivial equivalence relation @@ -22,5 +25,17 @@ trait EqInstances extends kernel.instances.EqInstances { Eq.instance { (left, right) => fa.eqv(left._1, right._1) && fb.eqv(left._2, right._2) } + + def sum[A, B](fa: Eq[A], fb: Eq[B]): Eq[Either[A, B]] = + Eq.instance { (left, right) => + if (left.isRight) + if (right.isRight) + (left, right).mapN(fb.eqv).right.get + else false + else + if (right.isLeft) + (left.swap, right.swap).mapN(fa.eqv).right.get + else false + } } } diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index d441bf5d61..8b055d2a5b 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -1,9 +1,12 @@ package cats package instances +import cats.instances.either._ +import cats.syntax.apply._ + trait EquivInstances { - implicit val catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = - new ContravariantMonoidal[Equiv] { + implicit val catsDecideableForEquiv: Decideable[Equiv] = + new Decideable[Equiv] { /** * Defaults to trivially contracting the type @@ -28,5 +31,18 @@ trait EquivInstances { def equiv(l: (A, B), r: (A, B)): Boolean = fa.equiv(l._1, r._1) && fb.equiv(l._2, r._2) } + + def sum[A, B](fa: Equiv[A], fb: Equiv[B]): Equiv[Either[A, B]] = + new Equiv[Either[A, B]] { + def equiv(x: Either[A, B], y: Either[A, B]): Boolean = + if (x.isRight) + if (y.isRight) + (x, y).mapN(fb.equiv).right.get + else false + else + if (y.isLeft) + (x.swap, y.swap).mapN(fa.equiv).right.get + else false + } } } diff --git a/core/src/main/scala/cats/instances/function.scala b/core/src/main/scala/cats/instances/function.scala index b5ba248e79..1d4ae0d9e2 100644 --- a/core/src/main/scala/cats/instances/function.scala +++ b/core/src/main/scala/cats/instances/function.scala @@ -97,16 +97,19 @@ sealed private[instances] trait Function0Instances0 { } sealed private[instances] trait Function1Instances extends Function1Instances0 { - implicit def catsStdContravariantMonoidalForFunction1[R: Monoid]: ContravariantMonoidal[? => R] = - new ContravariantMonoidal[? => R] { - def unit: Unit => R = Function.const(Monoid[R].empty) - def contramap[A, B](fa: A => R)(f: B => A): B => R = + implicit def catsStdDecideableForPredicate: Decideable[? => Boolean] = + new Decideable[? => Boolean] { + def empty[A]: A => Boolean = Function.const(false) + def unit: Unit => Boolean = Function.const(true) + def contramap[A, B](fa: A => Boolean)(f: B => A): B => Boolean = fa.compose(f) - def product[A, B](fa: A => R, fb: B => R): ((A, B)) => R = + def product[A, B](fa: A => Boolean, fb: B => Boolean): ((A, B)) => Boolean = (ab: (A, B)) => ab match { - case (a, b) => Monoid[R].combine(fa(a), fb(b)) + case (a, b) => fa(a) && fb(b) } + def sum[A, B](fa: A => Boolean, fb: B => Boolean): Either[A, B] => Boolean = + either => either.fold(fa, fb) } implicit def catsStdMonadForFunction1[T1]: Monad[T1 => ?] = @@ -154,6 +157,17 @@ sealed private[instances] trait Function1Instances extends Function1Instances0 { implicit val catsStdMonoidKForFunction1: MonoidK[Endo] = Category[Function1].algebraK + implicit def catsStdContravariantMonoidalForFunction1[R: Monoid]: ContravariantMonoidal[? => R] = + new ContravariantMonoidal[? => R] { + def unit: Unit => R = Function.const(Monoid[R].empty) + def contramap[A, B](fa: A => R)(f: B => A): B => R = + fa.compose(f) + def product[A, B](fa: A => R, fb: B => R): ((A, B)) => R = + (ab: (A, B)) => + ab match { + case (a, b) => Monoid[R].combine(fa(a), fb(b)) + } + } } sealed private[instances] trait Function1Instances0 { diff --git a/core/src/main/scala/cats/instances/order.scala b/core/src/main/scala/cats/instances/order.scala index 873425952e..d8744011c7 100644 --- a/core/src/main/scala/cats/instances/order.scala +++ b/core/src/main/scala/cats/instances/order.scala @@ -1,12 +1,14 @@ package cats package instances +import cats.instances.either._ +import cats.syntax.apply._ import cats.kernel.instances.unit._ trait OrderInstances extends kernel.instances.OrderInstances { - implicit val catsContravariantMonoidalForOrder: ContravariantMonoidal[Order] = - new ContravariantMonoidal[Order] { + implicit val catsDecideableForOrder: Decideable[Order] = + new Decideable[Order] { /** * Provides trivial order @@ -27,5 +29,19 @@ trait OrderInstances extends kernel.instances.OrderInstances { if (z == 0) fb.compare(x._2, y._2) else z } } + + def sum[A, B](fa: Order[A], fb: Order[B]): Order[Either[A, B]] = + new Order[Either[A, B]] { + def compare(x: Either[A, B], y: Either[A, B]): Int = { + if (x.isRight) + if (y.isRight) + (x, y).mapN(fb.compare).right.get + else 1 + else + if (y.isLeft) + (x.swap, y.swap).mapN(fa.compare).right.get + else -1 + } + } } } From b290417a3914c60ee77c04811205d9092cfe3b11 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Wed, 7 Nov 2018 13:10:03 -0800 Subject: [PATCH 03/87] Another batch of instances --- core/src/main/scala/cats/Applicative.scala | 6 ++++++ core/src/main/scala/cats/Composed.scala | 8 ++++++++ core/src/main/scala/cats/data/Kleisli.scala | 11 +++++++++++ core/src/main/scala/cats/data/Nested.scala | 21 +++++++++++++++++---- 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/core/src/main/scala/cats/Applicative.scala b/core/src/main/scala/cats/Applicative.scala index 72fcbd6078..8936f398b1 100644 --- a/core/src/main/scala/cats/Applicative.scala +++ b/core/src/main/scala/cats/Applicative.scala @@ -137,6 +137,12 @@ import simulacrum.typeclass val G = ContravariantMonoidal[G] } + def composeDecideable[G[_]: Decideable]: Decideable[λ[α => F[G[α]]]] = + new ComposedApplicativeDecideable[F, G] { + val F = self + val G = Decideable[G] + } + /** * Returns the given argument (mapped to Unit) if `cond` is `false`, * otherwise, unit lifted into F. diff --git a/core/src/main/scala/cats/Composed.scala b/core/src/main/scala/cats/Composed.scala index 5cf97bbcd5..6e780f2ebc 100644 --- a/core/src/main/scala/cats/Composed.scala +++ b/core/src/main/scala/cats/Composed.scala @@ -131,6 +131,14 @@ private[cats] trait ComposedContravariantCovariant[F[_], G[_]] extends Contravar F.contramap(fga)(gb => G.map(gb)(f)) } +private[cats] trait ComposedApplicativeDecideable[F[_], G[_]] extends Decideable[λ[α => F[G[α]]]] with ComposedApplicativeContravariantMonoidal[F, G] { outer => + def F: Applicative[F] + def G: Decideable[G] + + def sum[A, B](fa: F[G[A]], fb: F[G[B]]): F[G[Either[A, B]]] = + F.map(F.product(fa, fb))(Function.tupled(G.sum)) +} + private[cats] trait ComposedApplicativeContravariantMonoidal[F[_], G[_]] extends ContravariantMonoidal[λ[α => F[G[α]]]] { outer => def F: Applicative[F] diff --git a/core/src/main/scala/cats/data/Kleisli.scala b/core/src/main/scala/cats/data/Kleisli.scala index 612d0529c9..f33da4a691 100644 --- a/core/src/main/scala/cats/data/Kleisli.scala +++ b/core/src/main/scala/cats/data/Kleisli.scala @@ -184,6 +184,10 @@ sealed abstract private[data] class KleisliInstances0 extends KleisliInstances0_ implicit def F: Monad[F] = F0 } + implicit def catsDataDecideableForKleisli[F[_], A]( + implicit F0: Decideable[F] + ): Decideable[Kleisli[F, A, ?]] = + new KleisliDecideable[F, A] { def F: Decideable[F] = F0 } } sealed abstract private[data] class KleisliInstances0_5 extends KleisliInstances1 { @@ -419,6 +423,13 @@ private[data] trait KleisliAlternative[F[_], A] implicit def F: Alternative[F] } +sealed private[data] trait KleisliDecideable[F[_], D] extends Decideable[Kleisli[F, D, ?]] with KleisliContravariantMonoidal[F, D] { + implicit def F: Decideable[F] + + def sum[A, B](fa: Kleisli[F, D, A], fb: Kleisli[F, D, B]): Kleisli[F, D, Either[A, B]] = + Kleisli(d => F.sum(fa.run(d), fb.run(d))) +} + sealed private[data] trait KleisliContravariantMonoidal[F[_], D] extends ContravariantMonoidal[Kleisli[F, D, ?]] { implicit def F: ContravariantMonoidal[F] diff --git a/core/src/main/scala/cats/data/Nested.scala b/core/src/main/scala/cats/data/Nested.scala index 0f86be9c58..23ee07c7b7 100644 --- a/core/src/main/scala/cats/data/Nested.scala +++ b/core/src/main/scala/cats/data/Nested.scala @@ -43,10 +43,10 @@ sealed abstract private[data] class NestedInstances extends NestedInstances0 { val FG: NonEmptyTraverse[λ[α => F[G[α]]]] = NonEmptyTraverse[F].compose[G] } - implicit def catsDataContravariantMonoidalForApplicativeForNested[F[_]: Applicative, G[_]: ContravariantMonoidal] - : ContravariantMonoidal[Nested[F, G, ?]] = - new NestedContravariantMonoidal[F, G] with NestedContravariant[F, G] { - val FG: ContravariantMonoidal[λ[α => F[G[α]]]] = Applicative[F].composeContravariantMonoidal[G] + implicit def catsDataDecideableForApplicativeForNested[F[_]: Applicative, G[_]: Decideable] + : Decideable[Nested[F, G, ?]] = + new NestedDecideable[F, G] with NestedContravariant[F, G] { + val FG: Decideable[λ[α => F[G[α]]]] = Applicative[F].composeDecideable[G] } implicit def catsDataDeferForNested[F[_], G[_]](implicit F: Defer[F]): Defer[Nested[F, G, ?]] = @@ -75,6 +75,12 @@ sealed abstract private[data] class NestedInstances0 extends NestedInstances1 { implicit val F: Functor[F] = F0 implicit val G: FunctorFilter[G] = G0 } + + implicit def catsDataContravariantMonoidalForApplicativeForNested[F[_]: Applicative, G[_]: ContravariantMonoidal] + : ContravariantMonoidal[Nested[F, G, ?]] = + new NestedContravariantMonoidal[F, G] with NestedContravariant[F, G] { + val FG: ContravariantMonoidal[λ[α => F[G[α]]]] = Applicative[F].composeContravariantMonoidal[G] + } } sealed abstract private[data] class NestedInstances1 extends NestedInstances2 { @@ -329,6 +335,13 @@ private[data] trait NestedContravariant[F[_], G[_]] extends Contravariant[Nested Nested(FG.contramap(fga.value)(f)) } +private[data] trait NestedDecideable[F[_], G[_]] extends Decideable[Nested[F, G, ?]] with NestedContravariantMonoidal[F, G] { + def FG: Decideable[λ[α => F[G[α]]]] + + def sum[A, B](fa: Nested[F, G, A], fb: Nested[F, G, B]): Nested[F, G, Either[A, B]] = + Nested(FG.sum(fa.value, fb.value)) +} + private[data] trait NestedContravariantMonoidal[F[_], G[_]] extends ContravariantMonoidal[Nested[F, G, ?]] { def FG: ContravariantMonoidal[λ[α => F[G[α]]]] From 8ebe56472fbee268dfe6c2be480403e118060809 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Wed, 7 Nov 2018 13:20:54 -0800 Subject: [PATCH 04/87] Tuple2K instance --- core/src/main/scala/cats/data/Tuple2K.scala | 46 ++++++++++++++------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/core/src/main/scala/cats/data/Tuple2K.scala b/core/src/main/scala/cats/data/Tuple2K.scala index adbc79bbaf..69ff4f239a 100644 --- a/core/src/main/scala/cats/data/Tuple2K.scala +++ b/core/src/main/scala/cats/data/Tuple2K.scala @@ -33,13 +33,13 @@ sealed abstract private[data] class Tuple2KInstances extends Tuple2KInstances0 { def F: Show[F[A]] = FF def G: Show[G[A]] = GF } - implicit def catsDataContravariantMonoidalForTuple2k[F[_], G[_]]( - implicit FD: ContravariantMonoidal[F], - GD: ContravariantMonoidal[G] - ): ContravariantMonoidal[λ[α => Tuple2K[F, G, α]]] = - new Tuple2KContravariantMonoidal[F, G] with Tuple2KContravariant[F, G] { - def F: ContravariantMonoidal[F] = FD - def G: ContravariantMonoidal[G] = GD + implicit def catsDataDecideableForTuple2k[F[_], G[_]]( + implicit FD: Decideable[F], + GD: Decideable[G] + ): Decideable[λ[α => Tuple2K[F, G, α]]] = + new Tuple2KDecideable[F, G] with Tuple2KContravariant[F, G] { + def F: Decideable[F] = FD + def G: Decideable[G] = GD } implicit def catsDataDeferForTuple2K[F[_], G[_]](implicit F: Defer[F], G: Defer[G]): Defer[Tuple2K[F, G, ?]] = @@ -60,13 +60,14 @@ sealed abstract private[data] class Tuple2KInstances0 extends Tuple2KInstances1 def F: Traverse[F] = FF def G: Traverse[G] = GF } - implicit def catsDataContravariantForTuple2K[F[_], G[_]]( - implicit FC: Contravariant[F], - GC: Contravariant[G] - ): Contravariant[λ[α => Tuple2K[F, G, α]]] = new Tuple2KContravariant[F, G] { - def F: Contravariant[F] = FC - def G: Contravariant[G] = GC - } + implicit def catsDataContravariantMonoidalForTuple2k[F[_], G[_]]( + implicit FD: ContravariantMonoidal[F], + GD: ContravariantMonoidal[G] + ): ContravariantMonoidal[λ[α => Tuple2K[F, G, α]]] = + new Tuple2KContravariantMonoidal[F, G] with Tuple2KContravariant[F, G] { + def F: ContravariantMonoidal[F] = FD + def G: ContravariantMonoidal[G] = GD + } implicit def catsDataEqForTuple2K[F[_], G[_], A](implicit FF: Eq[F[A]], GG: Eq[G[A]]): Eq[Tuple2K[F, G, A]] = new Eq[Tuple2K[F, G, A]] { def eqv(x: Tuple2K[F, G, A], y: Tuple2K[F, G, A]): Boolean = @@ -87,6 +88,15 @@ sealed abstract private[data] class Tuple2KInstances1 extends Tuple2KInstances2 def F: Foldable[F] = FF def G: Foldable[G] = GF } + + implicit def catsDataContravariantForTuple2K[F[_], G[_]]( + implicit FC: Contravariant[F], + GC: Contravariant[G] + ): Contravariant[λ[α => Tuple2K[F, G, α]]] = new Tuple2KContravariant[F, G] { + def F: Contravariant[F] = FC + def G: Contravariant[G] = GC + } + } sealed abstract private[data] class Tuple2KInstances2 extends Tuple2KInstances3 { @@ -197,6 +207,14 @@ sealed private[data] trait Tuple2KContravariant[F[_], G[_]] extends Contravarian Tuple2K(F.contramap(fa.first)(f), G.contramap(fa.second)(f)) } +sealed private[data] trait Tuple2KDecideable[F[_], G[_]] extends Decideable[λ[α => Tuple2K[F, G, α]]] with Tuple2KContravariantMonoidal[F, G] { + def F: Decideable[F] + def G: Decideable[G] + + def sum[A, B](fa: Tuple2K[F, G, A], fb: Tuple2K[F, G, B]): Tuple2K[F, G, Either[A, B]] = + Tuple2K(F.sum(fa.first, fb.first), G.sum(fa.second, fb.second)) +} + sealed private[data] trait Tuple2KContravariantMonoidal[F[_], G[_]] extends ContravariantMonoidal[λ[α => Tuple2K[F, G, α]]] { def F: ContravariantMonoidal[F] From 4ae9ba0278207a2b29cd817f158bea82215aa038 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Wed, 7 Nov 2018 13:24:28 -0800 Subject: [PATCH 05/87] IdT instance --- core/src/main/scala/cats/data/IdT.scala | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/src/main/scala/cats/data/IdT.scala b/core/src/main/scala/cats/data/IdT.scala index 21700a2712..4ccf00d4cd 100644 --- a/core/src/main/scala/cats/data/IdT.scala +++ b/core/src/main/scala/cats/data/IdT.scala @@ -73,6 +73,13 @@ sealed private[data] trait IdTApplicative[F[_]] extends Applicative[IdT[F, ?]] w def pure[A](a: A): IdT[F, A] = IdT.pure(a) } +sealed private[data] trait IdTDecideable[F[_]] extends Decideable[IdT[F, ?]] with IdTContravariantMonoidal[F] { + implicit val F0: Decideable[F] + + override def sum[A, B](fa: IdT[F, A], fb: IdT[F, B]): IdT[F, Either[A, B]] = + IdT(F0.sum(fa.value, fb.value)) +} + sealed private[data] trait IdTContravariantMonoidal[F[_]] extends ContravariantMonoidal[IdT[F, ?]] { implicit val F0: ContravariantMonoidal[F] @@ -148,6 +155,7 @@ sealed abstract private[data] class IdTInstances8 { sealed abstract private[data] class IdTInstances7 extends IdTInstances8 { implicit def catsDataCommutativeMonadForIdT[F[_]](implicit F: CommutativeMonad[F]): CommutativeMonad[IdT[F, ?]] = new IdTMonad[F] with CommutativeMonad[IdT[F, ?]] { implicit val F0: CommutativeMonad[F] = F } + } sealed abstract private[data] class IdTInstances6 extends IdTInstances7 { @@ -160,6 +168,11 @@ sealed abstract private[data] class IdTInstances6 extends IdTInstances7 { sealed abstract private[data] class IdTInstances5 extends IdTInstances6 { implicit def catsDataFunctorForIdT[F[_]](implicit F: Functor[F]): Functor[IdT[F, ?]] = new IdTFunctor[F] { implicit val F0: Functor[F] = F } + + implicit def catsDataDecideableForIdT[F[_]]( + implicit F: Decideable[F] + ): Decideable[IdT[F, ?]] = + new IdTDecideable[F] { implicit val F0: Decideable[F] = F } } sealed abstract private[data] class IdTInstances4 extends IdTInstances5 { From 6ceae06b9c4d4f226acee40c14b6959f2faaadfb Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Wed, 7 Nov 2018 16:05:12 -0800 Subject: [PATCH 06/87] Draft law --- .../main/scala/cats/laws/DecideableLaws.scala | 22 +++++++++++ .../laws/discipline/DecideableTests.scala | 39 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 laws/src/main/scala/cats/laws/DecideableLaws.scala create mode 100644 laws/src/main/scala/cats/laws/discipline/DecideableTests.scala diff --git a/laws/src/main/scala/cats/laws/DecideableLaws.scala b/laws/src/main/scala/cats/laws/DecideableLaws.scala new file mode 100644 index 0000000000..102c047ab4 --- /dev/null +++ b/laws/src/main/scala/cats/laws/DecideableLaws.scala @@ -0,0 +1,22 @@ +package cats +package laws + +trait DecideableLaws[F[_]] extends ContravariantMonoidalLaws[F] { + implicit override def F: Decideable[F] + + def decideableDecideRightAbsorption[A](fa: F[A]): IsEq[F[A]] = + (F.decide(fa, F.trivial[A])(Right.apply[A, A])) <-> F.trivial[A] + + def decideableDecideLeftUnit[A](fa: F[A]): IsEq[F[A]] = + (F.decide(F.trivial[A], fa))(Right.apply[A, A]) <-> fa + + def decideableLeftDistributivity[A, B](fa: F[A], fa2: F[A], f: B => A): IsEq[F[B]] = F.decide(fa, fa2)(f andThen Left.apply) <-> F.contramap(fa)(f) + + def decideableRightDistributivity[A, B](fa: F[A], fa2: F[A], f: B => A): IsEq[F[B]] = F.decide(fa, fa2)(f andThen Right.apply) <-> F.contramap(fa2)(f) + +} + +object DecideableLaws { + def apply[F[_]](implicit ev: Decideable[F]): DecideableLaws[F] = + new DecideableLaws[F] { def F: Decideable[F] = ev } +} diff --git a/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala new file mode 100644 index 0000000000..ba54d3a5bf --- /dev/null +++ b/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala @@ -0,0 +1,39 @@ +package cats +package laws +package discipline + +import cats.laws.discipline.SemigroupalTests.Isomorphisms +import org.scalacheck.{Arbitrary, Cogen} +import org.scalacheck.Prop._ + +trait DecideableTests[F[_]] extends ContravariantMonoidalTests[F] { + def laws: DecideableLaws[F] + + def decideable[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit + arbFA: Arbitrary[F[A]], + arbFB: Arbitrary[F[B]], + arbFC: Arbitrary[F[C]], + CogenA: Cogen[A], + CogenB: Cogen[B], + CogenC: Cogen[C], + EqFA: Eq[F[A]], + EqFB: Eq[F[B]], + EqFC: Eq[F[C]], + EqFABC: Eq[F[(A, B, C)]], + iso: Isomorphisms[F]): RuleSet = + new RuleSet { + val name = "decideable" + val parents = Seq(contravariantMonoidal[A, B, C]) + val bases = Seq.empty + val props = Seq( + "decideable right absorption" -> + forAll(laws.decideableDecideRightAbsorption[A] _), + "decieable left unit" -> + forAll(laws.decideableDecideLeftUnit[A] _), + "decideable left distributivity" -> + forAll(laws.decideableLeftDistributivity[A, B] _), + "decideable right distributivity" -> + forAll(laws.decideableRightDistributivity[A, B] _) + ) + } +} From 764b8ca444eaaa235cfe4d77002c041a4bf6fcd4 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Fri, 9 Nov 2018 16:48:41 -0800 Subject: [PATCH 07/87] Some instance fixes... --- core/src/main/scala/cats/Composed.scala | 4 +- core/src/main/scala/cats/data/Const.scala | 6 ++- core/src/main/scala/cats/data/Kleisli.scala | 4 +- core/src/main/scala/cats/data/Nested.scala | 4 +- core/src/main/scala/cats/data/Op.scala | 41 ++++++++++++++----- core/src/main/scala/cats/data/OptionT.scala | 31 ++++++++------ core/src/main/scala/cats/data/Tuple2K.scala | 4 +- core/src/main/scala/cats/data/WriterT.scala | 19 +++++---- core/src/main/scala/cats/instances/eq.scala | 7 ++-- .../src/main/scala/cats/instances/equiv.scala | 7 ++-- .../src/main/scala/cats/instances/order.scala | 10 ++--- .../main/scala/cats/instances/ordering.scala | 18 +++++++- 12 files changed, 102 insertions(+), 53 deletions(-) diff --git a/core/src/main/scala/cats/Composed.scala b/core/src/main/scala/cats/Composed.scala index 6e780f2ebc..c83e7b7987 100644 --- a/core/src/main/scala/cats/Composed.scala +++ b/core/src/main/scala/cats/Composed.scala @@ -131,7 +131,9 @@ private[cats] trait ComposedContravariantCovariant[F[_], G[_]] extends Contravar F.contramap(fga)(gb => G.map(gb)(f)) } -private[cats] trait ComposedApplicativeDecideable[F[_], G[_]] extends Decideable[λ[α => F[G[α]]]] with ComposedApplicativeContravariantMonoidal[F, G] { outer => +private[cats] trait ComposedApplicativeDecideable[F[_], G[_]] + extends Decideable[λ[α => F[G[α]]]] + with ComposedApplicativeContravariantMonoidal[F, G] { outer => def F: Applicative[F] def G: Decideable[G] diff --git a/core/src/main/scala/cats/data/Const.scala b/core/src/main/scala/cats/data/Const.scala index 107e0352dc..f811f854e0 100644 --- a/core/src/main/scala/cats/data/Const.scala +++ b/core/src/main/scala/cats/data/Const.scala @@ -122,13 +122,15 @@ sealed abstract private[data] class ConstInstances extends ConstInstances0 { sealed abstract private[data] class ConstInstances0 extends ConstInstances1 { - implicit def catsDataContravariantMonoidalForConst[D: Monoid]: ContravariantMonoidal[Const[D, ?]] = - new ContravariantMonoidal[Const[D, ?]] { + implicit def catsDataDecideableForConst[D: Monoid]: Decideable[Const[D, ?]] = + new Decideable[Const[D, ?]] { override def unit = Const.empty[D, Unit] override def contramap[A, B](fa: Const[D, A])(f: B => A): Const[D, B] = fa.retag[B] override def product[A, B](fa: Const[D, A], fb: Const[D, B]): Const[D, (A, B)] = fa.retag[(A, B)].combine(fb.retag[(A, B)]) + def sum[A, B](fa: Const[D, A], fb: Const[D, B]): Const[D, Either[A, B]] = + fa.retag[Either[A, B]].combine(fb.retag[Either[A, B]]) } implicit def catsDataCommutativeApplicativeForConst[C]( diff --git a/core/src/main/scala/cats/data/Kleisli.scala b/core/src/main/scala/cats/data/Kleisli.scala index f33da4a691..540deb6036 100644 --- a/core/src/main/scala/cats/data/Kleisli.scala +++ b/core/src/main/scala/cats/data/Kleisli.scala @@ -423,7 +423,9 @@ private[data] trait KleisliAlternative[F[_], A] implicit def F: Alternative[F] } -sealed private[data] trait KleisliDecideable[F[_], D] extends Decideable[Kleisli[F, D, ?]] with KleisliContravariantMonoidal[F, D] { +sealed private[data] trait KleisliDecideable[F[_], D] + extends Decideable[Kleisli[F, D, ?]] + with KleisliContravariantMonoidal[F, D] { implicit def F: Decideable[F] def sum[A, B](fa: Kleisli[F, D, A], fb: Kleisli[F, D, B]): Kleisli[F, D, Either[A, B]] = diff --git a/core/src/main/scala/cats/data/Nested.scala b/core/src/main/scala/cats/data/Nested.scala index 23ee07c7b7..93c7702130 100644 --- a/core/src/main/scala/cats/data/Nested.scala +++ b/core/src/main/scala/cats/data/Nested.scala @@ -335,7 +335,9 @@ private[data] trait NestedContravariant[F[_], G[_]] extends Contravariant[Nested Nested(FG.contramap(fga.value)(f)) } -private[data] trait NestedDecideable[F[_], G[_]] extends Decideable[Nested[F, G, ?]] with NestedContravariantMonoidal[F, G] { +private[data] trait NestedDecideable[F[_], G[_]] + extends Decideable[Nested[F, G, ?]] + with NestedContravariantMonoidal[F, G] { def FG: Decideable[λ[α => F[G[α]]]] def sum[A, B](fa: Nested[F, G, A], fb: Nested[F, G, B]): Nested[F, G, Either[A, B]] = diff --git a/core/src/main/scala/cats/data/Op.scala b/core/src/main/scala/cats/data/Op.scala index 025d8623d4..71758e5b86 100644 --- a/core/src/main/scala/cats/data/Op.scala +++ b/core/src/main/scala/cats/data/Op.scala @@ -20,7 +20,8 @@ sealed abstract private[data] class OpInstances extends OpInstances0 { implicit def catsDataCategoryForOp[Arr[_, _]](implicit ArrC: Category[Arr]): Category[Op[Arr, ?, ?]] = new OpCategory[Arr] { def Arr: Category[Arr] = ArrC } - implicit def catsDataDecideableForOp[Arr[_, _], R](implicit ArrC: ArrowChoice[Arr], monn: Monoid[R]): Decideable[Op[Arr, R, ?]] = + implicit def catsDataDecideableForOp[Arr[_, _], R](implicit ArrC: ArrowChoice[Arr], + monn: Monoid[R]): Decideable[Op[Arr, R, ?]] = new OpDecideable[Arr, R] { def Arr: ArrowChoice[Arr] = ArrC def M: Monoid[R] = monn @@ -30,9 +31,18 @@ sealed abstract private[data] class OpInstances extends OpInstances0 { new OpEq[Arr, A, B] { def Arr: Eq[Arr[B, A]] = ArrEq } } -sealed abstract private[data] class OpInstances0 { +sealed abstract private[data] class OpInstances0 extends OpInstances1 { implicit def catsDataComposeForOp[Arr[_, _]](implicit ArrC: Compose[Arr]): Compose[Op[Arr, ?, ?]] = new OpCompose[Arr] { def Arr: Compose[Arr] = ArrC } + + implicit def catsDataContravariantMonoidalForOp[Arr[_, _], R](implicit ArrC: Arrow[Arr], + M0: Monoid[R]): ContravariantMonoidal[Op[Arr, R, ?]] = + new OpContravariantMonoidal[Arr, R] { def Arr = ArrC; def M = M0 } +} + +sealed abstract private[data] class OpInstances1 { + implicit def catsDataContravariantForOp[Arr[_, _], R](implicit ArrC: Arrow[Arr]): Contravariant[Op[Arr, R, ?]] = + new OpContravariant[Arr, R] { def Arr = ArrC } } private[data] trait OpCategory[Arr[_, _]] extends Category[Op[Arr, ?, ?]] with OpCompose[Arr] { @@ -48,23 +58,32 @@ private[data] trait OpCompose[Arr[_, _]] extends Compose[Op[Arr, ?, ?]] { f.compose(g) } -private[data] trait OpDecideable[Arr[_, _], R] extends Decideable[Op[Arr, R, ?]] { +private[data] trait OpDecideable[Arr[_, _], R] extends Decideable[Op[Arr, R, ?]] with OpContravariantMonoidal[Arr, R] { implicit def Arr: ArrowChoice[Arr] implicit def M: Monoid[R] + def sum[A, B](fa: Op[Arr, R, A], fb: Op[Arr, R, B]): Op[Arr, R, Either[A, B]] = + Op(Arr.choice(fa.run, fb.run)) +} + +private[data] trait OpContravariantMonoidal[Arr[_, _], R] + extends OpContravariant[Arr, R] + with ContravariantMonoidal[Op[Arr, R, ?]] { + implicit def Arr: Arrow[Arr] + implicit def M: Monoid[R] + def unit: Op[Arr, R, Unit] = Op(Arr.lift(Function.const(M.empty))) - def contramap[A, B](fa: Op[Arr, R, A])(f: B => A): Op[Arr, R, B] = - Op(Arr.compose(fa.run, Arr.lift(f))) - def product[A, B](fa: Op[Arr, R, A], fb: Op[Arr, R, B]): Op[Arr, R, (A, B)] = - Op(Arr.compose( - Arr.lift((M.combine _).tupled), - Arr.split(fa.run, fb.run))) + Op(Arr.compose(Arr.lift((M.combine _).tupled), Arr.split(fa.run, fb.run))) +} - def sum[A, B](fa: Op[Arr, R, A], fb: Op[Arr, R, B]): Op[Arr, R, Either[A, B]] = - Op(Arr.choice(fa.run, fb.run)) +private[data] trait OpContravariant[Arr[_, _], R] extends Contravariant[Op[Arr, R, ?]] { + implicit def Arr: Arrow[Arr] + + def contramap[A, B](fa: Op[Arr, R, A])(f: B => A): Op[Arr, R, B] = + Op(Arr.compose(fa.run, Arr.lift(f))) } private[data] trait OpEq[Arr[_, _], A, B] extends Eq[Op[Arr, A, B]] { diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index 528f815c5d..2ad6c580f0 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -267,19 +267,14 @@ sealed abstract private[data] class OptionTInstances extends OptionTInstances0 { G.map(Traverse[F].traverse(fa.value)(TraverseFilter[Option].filterA[G, A](_)(f)))(OptionT[F, A]) } - - implicit def catsDataDecideableForOptionT[F[_]](implicit F0: Decideable[F]): Decideable[OptionT[F, ?]] = - new OptionTDecideable[F] { implicit val F = F0 } } sealed abstract private[data] class OptionTInstances0 extends OptionTInstances1 { implicit def catsDataMonadErrorMonadForOptionT[F[_]](implicit F0: Monad[F]): MonadError[OptionT[F, ?], Unit] = new OptionTMonadErrorMonad[F] { implicit val F = F0 } - implicit def catsDataContravariantMonoidalForOptionT[F[_]]( - implicit F0: ContravariantMonoidal[F] - ): ContravariantMonoidal[OptionT[F, ?]] = - new OptionTContravariantMonoidal[F] { implicit val F = F0 } + implicit def catsDataDecideableForOptionT[F[_]](implicit F0: Decideable[F]): Decideable[OptionT[F, ?]] = + new OptionTDecideable[F] { implicit val F = F0 } implicit def catsDataMonoidKForOptionT[F[_]](implicit F0: Monad[F]): MonoidK[OptionT[F, ?]] = new OptionTMonoidK[F] { implicit val F = F0 } @@ -308,6 +303,12 @@ sealed abstract private[data] class OptionTInstances1 extends OptionTInstances2 implicit def catsDataMonadErrorForOptionT[F[_], E](implicit F0: MonadError[F, E]): MonadError[OptionT[F, ?], E] = new OptionTMonadError[F, E] { implicit val F = F0 } + + implicit def catsDataContravariantMonoidalForOptionT[F[_]]( + implicit F0: ContravariantMonoidal[F] + ): ContravariantMonoidal[OptionT[F, ?]] = + new OptionTContravariantMonoidal[F] { implicit val F = F0 } + } sealed abstract private[data] class OptionTInstances2 extends OptionTInstances3 { @@ -389,12 +390,16 @@ private trait OptionTDecideable[F[_]] extends Decideable[OptionT[F, ?]] with Opt def F: Decideable[F] def sum[A, B](fa: OptionT[F, A], fb: OptionT[F, B]): OptionT[F, Either[A, B]] = - OptionT(F.decide(fa.value, fb.value)( - (e: Option[Either[A, B]]) => e match { - case Some(Right(b)) => Right(Option(b)) - case Some(Left(a)) => Left(Option(a)) - case None => Left(None) - })) + OptionT( + F.decide(fa.value, fb.value)( + (e: Option[Either[A, B]]) => + e match { + case Some(Right(b)) => Right(Option(b)) + case Some(Left(a)) => Left(Option(a)) + case None => Left(None) + } + ) + ) } private trait OptionTContravariantMonoidal[F[_]] extends ContravariantMonoidal[OptionT[F, ?]] { diff --git a/core/src/main/scala/cats/data/Tuple2K.scala b/core/src/main/scala/cats/data/Tuple2K.scala index 69ff4f239a..821bc283c8 100644 --- a/core/src/main/scala/cats/data/Tuple2K.scala +++ b/core/src/main/scala/cats/data/Tuple2K.scala @@ -207,7 +207,9 @@ sealed private[data] trait Tuple2KContravariant[F[_], G[_]] extends Contravarian Tuple2K(F.contramap(fa.first)(f), G.contramap(fa.second)(f)) } -sealed private[data] trait Tuple2KDecideable[F[_], G[_]] extends Decideable[λ[α => Tuple2K[F, G, α]]] with Tuple2KContravariantMonoidal[F, G] { +sealed private[data] trait Tuple2KDecideable[F[_], G[_]] + extends Decideable[λ[α => Tuple2K[F, G, α]]] + with Tuple2KContravariantMonoidal[F, G] { def F: Decideable[F] def G: Decideable[G] diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index b319edf804..715d897e20 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -469,16 +469,21 @@ sealed private[data] trait WriterTAlternative[F[_], L] implicit override def F0: Alternative[F] } -sealed private[data] trait WriterTDecideable[F[_], L] extends WriterTContravariantMonoidal[F, L] with Decideable[WriterT[F, L, ?]] { +sealed private[data] trait WriterTDecideable[F[_], L] + extends WriterTContravariantMonoidal[F, L] + with Decideable[WriterT[F, L, ?]] { implicit def F0: Decideable[F] override def sum[A, B](fa: WriterT[F, L, A], fb: WriterT[F, L, B]): WriterT[F, L, Either[A, B]] = - WriterT(F0.decide(fa.run, fb.run)( - (e: (L, Either[A, B])) => - e match { - case (l, Right(b)) => Right((l, b)) - case (l, Left(a)) => Left((l, a)) - })) + WriterT( + F0.decide(fa.run, fb.run)( + (e: (L, Either[A, B])) => + e match { + case (l, Right(b)) => Right((l, b)) + case (l, Left(a)) => Left((l, a)) + } + ) + ) } sealed private[data] trait WriterTContravariantMonoidal[F[_], L] extends ContravariantMonoidal[WriterT[F, L, ?]] { diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index ac9983fece..38cc3a3062 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -32,10 +32,9 @@ trait EqInstances extends kernel.instances.EqInstances { if (right.isRight) (left, right).mapN(fb.eqv).right.get else false - else - if (right.isLeft) - (left.swap, right.swap).mapN(fa.eqv).right.get - else false + else if (right.isLeft) + (left.swap, right.swap).mapN(fa.eqv).right.get + else false } } } diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index 8b055d2a5b..e029017969 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -39,10 +39,9 @@ trait EquivInstances { if (y.isRight) (x, y).mapN(fb.equiv).right.get else false - else - if (y.isLeft) - (x.swap, y.swap).mapN(fa.equiv).right.get - else false + else if (y.isLeft) + (x.swap, y.swap).mapN(fa.equiv).right.get + else false } } } diff --git a/core/src/main/scala/cats/instances/order.scala b/core/src/main/scala/cats/instances/order.scala index d8744011c7..9d5f83eec0 100644 --- a/core/src/main/scala/cats/instances/order.scala +++ b/core/src/main/scala/cats/instances/order.scala @@ -32,16 +32,14 @@ trait OrderInstances extends kernel.instances.OrderInstances { def sum[A, B](fa: Order[A], fb: Order[B]): Order[Either[A, B]] = new Order[Either[A, B]] { - def compare(x: Either[A, B], y: Either[A, B]): Int = { + def compare(x: Either[A, B], y: Either[A, B]): Int = if (x.isRight) if (y.isRight) (x, y).mapN(fb.compare).right.get else 1 - else - if (y.isLeft) - (x.swap, y.swap).mapN(fa.compare).right.get - else -1 - } + else if (y.isLeft) + (x.swap, y.swap).mapN(fa.compare).right.get + else -1 } } } diff --git a/core/src/main/scala/cats/instances/ordering.scala b/core/src/main/scala/cats/instances/ordering.scala index 23cbd7e071..124c239d8a 100644 --- a/core/src/main/scala/cats/instances/ordering.scala +++ b/core/src/main/scala/cats/instances/ordering.scala @@ -1,11 +1,13 @@ package cats package instances +import cats.instances.either._ +import cats.syntax.apply._ import cats.kernel.instances.unit._ trait OrderingInstances { - implicit val catsContravariantMonoidalForOrdering: ContravariantMonoidal[Ordering] = - new ContravariantMonoidal[Ordering] { + implicit val catsDecideableForOrdering: Decideable[Ordering] = + new Decideable[Ordering] { /** * Note: resulting instances are law-abiding only when the functions used are injective (represent a one-to-one mapping) @@ -21,5 +23,17 @@ trait OrderingInstances { if (z == 0) fb.compare(x._2, y._2) else z } } + + def sum[A, B](fa: Ordering[A], fb: Ordering[B]): Ordering[Either[A, B]] = + new Ordering[Either[A, B]] { + def compare(x: Either[A, B], y: Either[A, B]): Int = + if (x.isRight) + if (y.isRight) + (x, y).mapN(fb.compare).right.get + else 1 + else if (y.isLeft) + (x.swap, y.swap).mapN(fa.compare).right.get + else -1 + } } } From 04b14336f87d50d4a63f5789d4556fc6d5a15ebc Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Fri, 9 Nov 2018 16:48:54 -0800 Subject: [PATCH 08/87] Scale back those insane laws --- .../main/scala/cats/laws/DecideableLaws.scala | 11 +-- .../laws/discipline/DecideableTests.scala | 94 ++++++++++++++----- 2 files changed, 73 insertions(+), 32 deletions(-) diff --git a/laws/src/main/scala/cats/laws/DecideableLaws.scala b/laws/src/main/scala/cats/laws/DecideableLaws.scala index 102c047ab4..2fdc042a7d 100644 --- a/laws/src/main/scala/cats/laws/DecideableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecideableLaws.scala @@ -5,15 +5,14 @@ trait DecideableLaws[F[_]] extends ContravariantMonoidalLaws[F] { implicit override def F: Decideable[F] def decideableDecideRightAbsorption[A](fa: F[A]): IsEq[F[A]] = - (F.decide(fa, F.trivial[A])(Right.apply[A, A])) <-> F.trivial[A] - - def decideableDecideLeftUnit[A](fa: F[A]): IsEq[F[A]] = (F.decide(F.trivial[A], fa))(Right.apply[A, A]) <-> fa - def decideableLeftDistributivity[A, B](fa: F[A], fa2: F[A], f: B => A): IsEq[F[B]] = F.decide(fa, fa2)(f andThen Left.apply) <-> F.contramap(fa)(f) - - def decideableRightDistributivity[A, B](fa: F[A], fa2: F[A], f: B => A): IsEq[F[B]] = F.decide(fa, fa2)(f andThen Right.apply) <-> F.contramap(fa2)(f) + def decideableSumAssociativity[A, B, C](fa: F[A], + fb: F[B], + fc: F[C]): (F[Either[A, Either[B, C]]], F[Either[Either[A, B], C]]) = + (F.sum(fa, F.sum(fb, fc)), F.sum(F.sum(fa, fb), fc)) + // What is the right distributivity law here? } object DecideableLaws { diff --git a/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala index ba54d3a5bf..0b3a60b1d6 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala @@ -2,7 +2,6 @@ package cats package laws package discipline -import cats.laws.discipline.SemigroupalTests.Isomorphisms import org.scalacheck.{Arbitrary, Cogen} import org.scalacheck.Prop._ @@ -10,30 +9,73 @@ trait DecideableTests[F[_]] extends ContravariantMonoidalTests[F] { def laws: DecideableLaws[F] def decideable[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit - arbFA: Arbitrary[F[A]], - arbFB: Arbitrary[F[B]], - arbFC: Arbitrary[F[C]], - CogenA: Cogen[A], - CogenB: Cogen[B], - CogenC: Cogen[C], - EqFA: Eq[F[A]], - EqFB: Eq[F[B]], - EqFC: Eq[F[C]], - EqFABC: Eq[F[(A, B, C)]], - iso: Isomorphisms[F]): RuleSet = - new RuleSet { - val name = "decideable" - val parents = Seq(contravariantMonoidal[A, B, C]) - val bases = Seq.empty - val props = Seq( - "decideable right absorption" -> - forAll(laws.decideableDecideRightAbsorption[A] _), - "decieable left unit" -> - forAll(laws.decideableDecideLeftUnit[A] _), - "decideable left distributivity" -> - forAll(laws.decideableLeftDistributivity[A, B] _), - "decideable right distributivity" -> - forAll(laws.decideableRightDistributivity[A, B] _) - ) + arbFA: Arbitrary[F[A]], + arbFB: Arbitrary[F[B]], + arbFC: Arbitrary[F[C]], + CogenA: Cogen[A], + CogenB: Cogen[B], + CogenC: Cogen[C], + EqFA: Eq[F[A]], + EqFB: Eq[F[B]], + EqFC: Eq[F[C]], + EqFABC: Eq[F[(A, B, C)]], + EqFEitABC: Eq[F[Either[Either[A, B], C]]], + iso: SemigroupalTests.Isomorphisms[F], + iso2: DecideableTests.Isomorphisms[F]): RuleSet = + new RuleSet { + val name = "decideable" + val parents = Seq(contravariantMonoidal[A, B, C]) + val bases = Seq.empty + val props = Seq( + "decideable right absorption" -> + forAll(laws.decideableDecideRightAbsorption[A] _), + "decideable sum associativity" -> forAll( + (fa: F[A], fb: F[B], fc: F[C]) => iso2.associativity(laws.decideableSumAssociativity[A, B, C](fa, fb, fc)) + ) + ) + } +} + +object DecideableTests { + def apply[F[_]: Decideable](implicit ev: Isomorphisms[F]): DecideableTests[F] = + new DecideableTests[F] { def laws: DecideableLaws[F] = DecideableLaws[F] } + + trait Isomorphisms[F[_]] { + def associativity[A, B, C]( + fs: (F[Either[A, Either[B, C]]], F[Either[Either[A, B], C]]) + ): IsEq[F[Either[Either[A, B], C]]] + def leftIdentity[A](fs: (F[Either[Nothing, A]], F[A])): IsEq[F[A]] + def rightIdentity[A](fs: (F[Either[A, Nothing]], F[A])): IsEq[F[A]] + } + + object Isomorphisms { + private def absurd[A](n: Nothing): A = n.asInstanceOf[A] + + import cats.kernel.laws._ + implicit def invariant[F[_]](implicit F: Invariant[F]): Isomorphisms[F] = + new Isomorphisms[F] { + def associativity[A, B, C]( + fs: (F[Either[A, Either[B, C]]], F[Either[Either[A, B], C]]) + ): IsEq[F[Either[Either[A, B], C]]] = + F.imap(fs._1) { + case Left(a) => Left(Left(a)) + case Right(Left(b)) => Left(Right(b)) + case Right(Right(c)) => Right(c) + } { + case Left(Left(a)) => Left(a) + case Left(Right(b)) => Right(Left(b)) + case Right(c) => Right(Right(c)) + } <-> fs._2 + + def leftIdentity[A](fs: (F[Either[Nothing, A]], F[A])): IsEq[F[A]] = + F.imap(fs._1) { case Right(a) => a; case Left(n) => absurd[A](n) } { (a: A) => + Right(a) + } <-> fs._2 + + def rightIdentity[A](fs: (F[Either[A, Nothing]], F[A])): IsEq[F[A]] = + F.imap(fs._1) { case Left(a) => a; case Right(n) => absurd[A](n) } { (a: A) => + Left(a) + } <-> fs._2 } + } } From 57abb07947bd9f03a3bac28022a0c5d888e32129 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Fri, 9 Nov 2018 16:49:05 -0800 Subject: [PATCH 09/87] Initial tests... --- tests/src/test/scala/cats/tests/EqSuite.scala | 8 +++---- .../test/scala/cats/tests/EquivSuite.scala | 4 +++- .../test/scala/cats/tests/FunctionSuite.scala | 6 +++++ .../src/test/scala/cats/tests/IdTSuite.scala | 7 ++++++ .../test/scala/cats/tests/KleisliSuite.scala | 11 +++++++++ .../test/scala/cats/tests/NestedSuite.scala | 9 +++++++ tests/src/test/scala/cats/tests/OpSuite.scala | 24 +++++++++++++++++++ .../test/scala/cats/tests/OptionTSuite.scala | 11 +++++---- .../test/scala/cats/tests/OrderSuite.scala | 7 +++--- .../test/scala/cats/tests/OrderingSuite.scala | 4 +++- .../test/scala/cats/tests/Tuple2KSuite.scala | 10 ++++++++ 11 files changed, 87 insertions(+), 14 deletions(-) diff --git a/tests/src/test/scala/cats/tests/EqSuite.scala b/tests/src/test/scala/cats/tests/EqSuite.scala index 91c16adf16..52314a8645 100644 --- a/tests/src/test/scala/cats/tests/EqSuite.scala +++ b/tests/src/test/scala/cats/tests/EqSuite.scala @@ -2,7 +2,7 @@ package cats package tests import cats.kernel.laws.discipline.SerializableTests -import cats.laws.discipline.ContravariantMonoidalTests +import cats.laws.discipline.DecideableTests import cats.laws.discipline.arbitrary._ import cats.laws.discipline.eq._ @@ -11,8 +11,8 @@ class EqSuite extends CatsSuite { Contravariant[Eq] Semigroupal[Eq] ContravariantSemigroupal[Eq] + Decideable[Eq] - checkAll("Eq[Int]", ContravariantMonoidalTests[Eq].contravariantMonoidal[Int, Int, Int]) - checkAll("ContravariantMonoidal[Eq]", SerializableTests.serializable(ContravariantMonoidal[Eq])) - + checkAll("Eq[Int]", DecideableTests[Eq].decideable[Int, Int, Int]) + checkAll("Decideable[Eq]", SerializableTests.serializable(Decideable[Eq])) } diff --git a/tests/src/test/scala/cats/tests/EquivSuite.scala b/tests/src/test/scala/cats/tests/EquivSuite.scala index 62bf7d5fc7..8f0679dab8 100644 --- a/tests/src/test/scala/cats/tests/EquivSuite.scala +++ b/tests/src/test/scala/cats/tests/EquivSuite.scala @@ -12,9 +12,11 @@ class EquivSuite extends CatsSuite { Semigroupal[Equiv] ContravariantSemigroupal[Equiv] ContravariantMonoidal[Equiv] + Decideable[Equiv] checkAll("Contravariant[Equiv]", ContravariantTests[Equiv].contravariant[Int, Int, Int]) checkAll("Semigroupal[Equiv]", SemigroupalTests[Equiv].semigroupal[Int, Int, Int]) checkAll("ContravariantMonoidal[Equiv]", ContravariantMonoidalTests[Equiv].contravariantMonoidal[Int, Int, Int]) - checkAll("ContravariantMonoidal[Equiv]", SerializableTests.serializable(ContravariantMonoidal[Equiv])) + checkAll("Decideable[Equiv]", DecideableTests[Equiv].decideable[Int, Int, Int]) + checkAll("Decideable[Equiv]", SerializableTests.serializable(Decideable[Equiv])) } diff --git a/tests/src/test/scala/cats/tests/FunctionSuite.scala b/tests/src/test/scala/cats/tests/FunctionSuite.scala index 1b56ca44a8..32374a46e2 100644 --- a/tests/src/test/scala/cats/tests/FunctionSuite.scala +++ b/tests/src/test/scala/cats/tests/FunctionSuite.scala @@ -125,6 +125,12 @@ class FunctionSuite extends CatsSuite { implicit val isoCodomain = SemigroupalTests.Isomorphisms.invariant[Function1[?, Long]] checkAll("Function1[?, Monoid]", ContravariantMonoidalTests[Function1[?, Long]].contravariantMonoidal[Int, Int, Int]) + // Isos for Decideable + implicit val isoCodomainBoolean = SemigroupalTests.Isomorphisms.invariant[Function1[?, Boolean]] + implicit val isoCoproductCodomain = DecideableTests.Isomorphisms.invariant[Function1[?, Boolean]] + checkAll("Function1[?, Boolean]", DecideableTests[Function1[?, Boolean]].decideable[Int, Int, Int]) + checkAll("Decideable[? => Boolean]", SerializableTests.serializable(Decideable[Function1[?, Boolean]])) + // serialization tests for the various Function1-related instances checkAll("Semigroup[String => Semi]", SerializableTests.serializable(Semigroup[String => Semi])) checkAll("CommutativeSemigroup[String => Semi]", diff --git a/tests/src/test/scala/cats/tests/IdTSuite.scala b/tests/src/test/scala/cats/tests/IdTSuite.scala index 6cb1ab9f8e..fe09a6b906 100644 --- a/tests/src/test/scala/cats/tests/IdTSuite.scala +++ b/tests/src/test/scala/cats/tests/IdTSuite.scala @@ -61,6 +61,13 @@ class IdTSuite extends CatsSuite { SerializableTests.serializable(ContravariantMonoidal[IdT[Const[String, ?], ?]])) } + { + implicit val coproductIso = DecideableTests.Isomorphisms.invariant[IdT[Const[String, ?], ?]] + checkAll("IdT[Const[String, ?], ?]", DecideableTests[IdT[Const[String, ?], ?]].decideable[Int, Int, Int]) + checkAll("Decideable[IdT[Const[String, ?], ?]]", + SerializableTests.serializable(Decideable[IdT[Const[String, ?], ?]])) + } + { implicit val F = ListWrapper.flatMap diff --git a/tests/src/test/scala/cats/tests/KleisliSuite.scala b/tests/src/test/scala/cats/tests/KleisliSuite.scala index e9bf90e1b8..d79e6784fd 100644 --- a/tests/src/test/scala/cats/tests/KleisliSuite.scala +++ b/tests/src/test/scala/cats/tests/KleisliSuite.scala @@ -113,6 +113,17 @@ class KleisliSuite extends CatsSuite { SerializableTests.serializable(Alternative[Kleisli[Option, Int, ?]])) } + { + implicit val catsDataDecideableForKleisli = + Kleisli.catsDataDecideableForKleisli[Const[String, ?], Int] + checkAll("Kleisli[Const[String, ?], Int, Int]", + DecideableTests[Kleisli[Const[String, ?], Int, ?]].decideable[Int, Int, Int]) + checkAll( + "Decideable[Kleisli[Option, Int, ?]]", + SerializableTests.serializable[Decideable[Kleisli[Const[String, ?], Int, ?]]](catsDataDecideableForKleisli) + ) + } + { implicit val catsDataContravariantMonoidalForKleisli = Kleisli.catsDataContravariantMonoidalForKleisli[Const[String, ?], Int] diff --git a/tests/src/test/scala/cats/tests/NestedSuite.scala b/tests/src/test/scala/cats/tests/NestedSuite.scala index a35c423072..5b202dcbd5 100644 --- a/tests/src/test/scala/cats/tests/NestedSuite.scala +++ b/tests/src/test/scala/cats/tests/NestedSuite.scala @@ -96,6 +96,15 @@ class NestedSuite extends CatsSuite { SerializableTests.serializable(ContravariantMonoidal[Nested[Option, Const[String, ?], ?]])) } + { + // Applicative + Decideable functor compositoin + implicit val coproductIsos = DecideableTests.Isomorphisms.invariant[Nested[Option, Const[String, ?], ?]] + checkAll("Nested[Option, Const[String, ?], ?]", + DecideableTests[Nested[Option, Const[String, ?], ?]].decideable[Int, Int, Int]) + checkAll("Decideable[Nested[Option, Const[String, ?], ?]]", + SerializableTests.serializable(Decideable[Nested[Option, Const[String, ?], ?]])) + } + { // Contravariant + Contravariant = Functor type ConstInt[A] = Const[Int, A] diff --git a/tests/src/test/scala/cats/tests/OpSuite.scala b/tests/src/test/scala/cats/tests/OpSuite.scala index 0b2e4ed358..213961de64 100644 --- a/tests/src/test/scala/cats/tests/OpSuite.scala +++ b/tests/src/test/scala/cats/tests/OpSuite.scala @@ -21,6 +21,30 @@ class OpSuite extends CatsSuite { checkAll("Category[Op[Function1, ?, ?]]", SerializableTests.serializable(Category[Op[Function1, ?, ?]])) } + { + implicit val catsDataDecideableForOp = Op.catsDataDecideableForOp[Function1, Int] + implicit val coproductIsos = DecideableTests.Isomorphisms.invariant[Op[Function1, Int, ?]] + checkAll("Op[Function1, Monoid, ?]", DecideableTests[Op[Function1, Int, ?]].decideable[Char, Char, Char]) + checkAll("Decideable[Op[Function1, Monoid, ?]]", SerializableTests.serializable(Decideable[Op[Function1, Int, ?]])) + } + + { + implicit val catsDataContravariantMonoidalForOp = Op.catsDataContravariantMonoidalForOp[Function1, Int] + checkAll("Op[Function1, Monoid, ?]", + ContravariantMonoidalTests[Op[Function1, Int, ?]].contravariantMonoidal[Char, Char, Char]) + checkAll("ContravariantMonoidal[Op[Function1, Monoid, ?]]", + SerializableTests.serializable(ContravariantMonoidal[Op[Function1, Int, ?]])) + + } + + { + implicit val catsDataContravariantForOp = Op.catsDataContravariantForOp[Function1, Unit] + checkAll("Op[Function1, Unit, ?]", ContravariantTests[Op[Function1, Unit, ?]].contravariant[Char, Char, Char]) + checkAll("Contravariant[Op[Function1, Unit, ?]]", + SerializableTests.serializable(Contravariant[Op[Function1, Int, ?]])) + + } + /** * Testing that implicit resolution works. If it compiles, the "test" passes. */ diff --git a/tests/src/test/scala/cats/tests/OptionTSuite.scala b/tests/src/test/scala/cats/tests/OptionTSuite.scala index 9b9e25160d..9e6f362380 100644 --- a/tests/src/test/scala/cats/tests/OptionTSuite.scala +++ b/tests/src/test/scala/cats/tests/OptionTSuite.scala @@ -90,11 +90,12 @@ class OptionTSuite extends CatsSuite { } { - // F has a ContravariantMonoidal - checkAll("OptionT[Const[String, ?], Int]", - ContravariantMonoidalTests[OptionT[Const[String, ?], ?]].contravariantMonoidal[Int, Int, Int]) - checkAll("ContravariantMonoidal[OptionT[Const[String, ?], Int]]", - SerializableTests.serializable(ContravariantMonoidal[OptionT[Const[String, ?], ?]])) + // F has a Decideable + implicit val iso = SemigroupalTests.Isomorphisms.invariant[OptionT[Const[String, ?], ?]] + + checkAll("OptionT[Const[String, ?], Int]", DecideableTests[OptionT[Const[String, ?], ?]].decideable[Int, Int, Int]) + checkAll("Decideable[OptionT[Const[String, ?], Int]]", + SerializableTests.serializable(Decideable[OptionT[Const[String, ?], ?]])) } { diff --git a/tests/src/test/scala/cats/tests/OrderSuite.scala b/tests/src/test/scala/cats/tests/OrderSuite.scala index 44f4e3c925..c843ab9b5e 100644 --- a/tests/src/test/scala/cats/tests/OrderSuite.scala +++ b/tests/src/test/scala/cats/tests/OrderSuite.scala @@ -3,7 +3,7 @@ package tests import Helpers.Ord import cats.kernel.laws.discipline.{OrderTests, SerializableTests} -import cats.laws.discipline.ContravariantMonoidalTests +import cats.laws.discipline.DecideableTests import cats.laws.discipline.arbitrary._ import cats.laws.discipline.eq._ @@ -12,6 +12,7 @@ class OrderSuite extends CatsSuite { Invariant[Order] Contravariant[Order] ContravariantMonoidal[Order] + Decideable[Order] } checkAll("Int", OrderTests[Int].order) @@ -19,8 +20,8 @@ class OrderSuite extends CatsSuite { checkAll("Float", OrderTests[Float].order) checkAll("Long", OrderTests[Long].order) - checkAll("Order", ContravariantMonoidalTests[Order].contravariantMonoidal[Int, Int, Int]) - checkAll("ContravariantMonoidal[Order]", SerializableTests.serializable(ContravariantMonoidal[Order])) + checkAll("Order", DecideableTests[Order].decideable[Int, Int, Int]) + checkAll("Decideable[Order]", SerializableTests.serializable(Decideable[Order])) test("order ops syntax") { forAll { (i: Ord, j: Ord) => diff --git a/tests/src/test/scala/cats/tests/OrderingSuite.scala b/tests/src/test/scala/cats/tests/OrderingSuite.scala index 1996e01b64..adea87e519 100644 --- a/tests/src/test/scala/cats/tests/OrderingSuite.scala +++ b/tests/src/test/scala/cats/tests/OrderingSuite.scala @@ -12,9 +12,11 @@ class OrderingSuite extends CatsSuite { Semigroupal[Ordering] ContravariantSemigroupal[Ordering] ContravariantMonoidal[Ordering] + Decideable[Ordering] checkAll("Contravariant[Ordering]", ContravariantTests[Ordering].contravariant[Int, Int, Int]) checkAll("Semigroupal[Ordering]", SemigroupalTests[Ordering].semigroupal[Int, Int, Int]) checkAll("ContravariantMonoidal[Ordering]", ContravariantMonoidalTests[Ordering].contravariantMonoidal[Int, Int, Int]) - checkAll("ContravariantMonoidal[Ordering]", SerializableTests.serializable(ContravariantMonoidal[Ordering])) + checkAll("Decideable[Ordering]", DecideableTests[Ordering].decideable[Int, Int, Int]) + checkAll("ContravariantMonoidal[Ordering]", SerializableTests.serializable(Decideable[Ordering])) } diff --git a/tests/src/test/scala/cats/tests/Tuple2KSuite.scala b/tests/src/test/scala/cats/tests/Tuple2KSuite.scala index bf9e7be506..d90bedf157 100644 --- a/tests/src/test/scala/cats/tests/Tuple2KSuite.scala +++ b/tests/src/test/scala/cats/tests/Tuple2KSuite.scala @@ -33,6 +33,16 @@ class Tuple2KSuite extends CatsSuite { SerializableTests.serializable(ContravariantMonoidal[λ[α => Tuple2K[Const[String, ?], Const[Int, ?], α]]]) ) + // Coproduct isos for DecideableTests + implicit val coproductIso = DecideableTests.Isomorphisms.invariant[Tuple2K[Const[String, ?], Const[Int, ?], ?]] + + checkAll("Tuple2K[Const[String, ?], Const[Int, ?], Long]", + DecideableTests[λ[α => Tuple2K[Const[String, ?], Const[Int, ?], α]]].decideable[Long, Long, Long]) + checkAll( + "Decideable[Tuple2K[Const[String, ?], Const[Int, ?], Long]]", + SerializableTests.serializable(Decideable[λ[α => Tuple2K[Const[String, ?], Const[Int, ?], α]]]) + ) + checkAll("Show[Tuple2K[Option, Option, Int]]", SerializableTests.serializable(Show[Tuple2K[Option, Option, Int]])) { From ad4c062655df4fbd41cfdbf7a6f7fc16ba816491 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Fri, 9 Nov 2018 16:49:13 -0800 Subject: [PATCH 10/87] First pass at docs --- docs/src/main/tut/typeclasses/decideable.md | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/src/main/tut/typeclasses/decideable.md diff --git a/docs/src/main/tut/typeclasses/decideable.md b/docs/src/main/tut/typeclasses/decideable.md new file mode 100644 index 0000000000..f0c7abfe72 --- /dev/null +++ b/docs/src/main/tut/typeclasses/decideable.md @@ -0,0 +1,30 @@ +--- +layout: docs +title: "Decideable" +section: "typeclasses" +source: "core/src/main/scala/cats/Decideable.scala" +scaladoc: "#cats.Decideable" +--- +# Decideable + +The `Decideable` type class is an extension of [`ContravariantMonoidal`](contravariantmonoidal.html) that allows the +definition of a `sum` function, allowing us to make choices in consuming our input. + +It is the contravariant analogue of the [`Alternative`](alternative.html) type class. + +```tut:silent +import cats.ContravariantMonoidal + +trait Decideable[F[_]] extends ContravariantMonoidal[F] { + def sum[A, B](fa: F[A], fb: F[B]): Either[F[A], F[B]] + + def decide[A, B, C](fa: F[A], fb: F[B])(f: C => Either[A, B]): F[C] = + contramap(sum(fa, fb))(f) +} +``` + +`sum` lets us implement the `decide` function. Note how `decide` says, no matter what the outcome of a possibly multi-outcome procedure, I can consume either outcome. + +In other words, if we have two contexts `F[A]` and `F[B]` and we have a procedure `C => Either[A, B]` that could produce either an A or a B depending on the input, we have a way to produce a context `F[C]`. + +The classic example of a `Decideable` is that of predicates `A => Boolean`, leaning on the fact that both `&&` and `^` are valid monoids on `Boolean`. From 244e7a5d65a345759a88df7e3dfb1789379da56a Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Fri, 9 Nov 2018 20:39:32 -0800 Subject: [PATCH 11/87] Retuned laws with mostly reasonable right distributivity --- .../main/scala/cats/laws/DecideableLaws.scala | 14 +++++--- .../laws/discipline/DecideableTests.scala | 32 ++++++++++--------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/laws/src/main/scala/cats/laws/DecideableLaws.scala b/laws/src/main/scala/cats/laws/DecideableLaws.scala index 2fdc042a7d..26fd273557 100644 --- a/laws/src/main/scala/cats/laws/DecideableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecideableLaws.scala @@ -7,12 +7,18 @@ trait DecideableLaws[F[_]] extends ContravariantMonoidalLaws[F] { def decideableDecideRightAbsorption[A](fa: F[A]): IsEq[F[A]] = (F.decide(F.trivial[A], fa))(Right.apply[A, A]) <-> fa - def decideableSumAssociativity[A, B, C](fa: F[A], - fb: F[B], - fc: F[C]): (F[Either[A, Either[B, C]]], F[Either[Either[A, B], C]]) = + def decideableSumAssociativity[A, B, C](fa: F[A], fb: F[B], fc: F[C]): (F[Either[A, Either[B, C]]], F[Either[Either[A, B], C]]) = (F.sum(fa, F.sum(fb, fc)), F.sum(F.sum(fa, fb), fc)) - // What is the right distributivity law here? + def decideableRightDistributivity[A, B, C](fa: F[A], fb: F[B], f: C => A, g: C => B): IsEq[F[Either[C, C]]] = + F.contramap(F.sum(fa, fb))( + (eit: Either[C, C]) => + eit.fold( + f andThen Left.apply, + g andThen Right.apply) + ) <-> F.sum( + F.contramap(fa)(f), + F.contramap(fb)(g)) } object DecideableLaws { diff --git a/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala index 0b3a60b1d6..859fdb6604 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala @@ -9,19 +9,20 @@ trait DecideableTests[F[_]] extends ContravariantMonoidalTests[F] { def laws: DecideableLaws[F] def decideable[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit - arbFA: Arbitrary[F[A]], - arbFB: Arbitrary[F[B]], - arbFC: Arbitrary[F[C]], - CogenA: Cogen[A], - CogenB: Cogen[B], - CogenC: Cogen[C], - EqFA: Eq[F[A]], - EqFB: Eq[F[B]], - EqFC: Eq[F[C]], - EqFABC: Eq[F[(A, B, C)]], - EqFEitABC: Eq[F[Either[Either[A, B], C]]], - iso: SemigroupalTests.Isomorphisms[F], - iso2: DecideableTests.Isomorphisms[F]): RuleSet = + arbFA: Arbitrary[F[A]], + arbFB: Arbitrary[F[B]], + arbFC: Arbitrary[F[C]], + CogenA: Cogen[A], + CogenB: Cogen[B], + CogenC: Cogen[C], + EqFA: Eq[F[A]], + EqFB: Eq[F[B]], + EqFC: Eq[F[C]], + EqFABC: Eq[F[(A, B, C)]], + EqCC: Eq[F[Either[C, C]]], + EqFEitABC: Eq[F[Either[Either[A, B], C]]], + iso: SemigroupalTests.Isomorphisms[F], + iso2: DecideableTests.Isomorphisms[F]): RuleSet = new RuleSet { val name = "decideable" val parents = Seq(contravariantMonoidal[A, B, C]) @@ -30,8 +31,9 @@ trait DecideableTests[F[_]] extends ContravariantMonoidalTests[F] { "decideable right absorption" -> forAll(laws.decideableDecideRightAbsorption[A] _), "decideable sum associativity" -> forAll( - (fa: F[A], fb: F[B], fc: F[C]) => iso2.associativity(laws.decideableSumAssociativity[A, B, C](fa, fb, fc)) - ) + (fa: F[A], fb: F[B], fc: F[C]) => iso2.associativity(laws.decideableSumAssociativity[A, B, C](fa, fb, fc))), + "decideable right distributivity" -> + forAll(laws.decideableRightDistributivity[A, B, C] _) ) } } From a8f80792adf7c14dcb68b37641c95c3232f3727b Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Fri, 9 Nov 2018 20:39:59 -0800 Subject: [PATCH 12/87] Comment out dead code warning --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 63f45e5f5b..04b7a0b103 100644 --- a/build.sbt +++ b/build.sbt @@ -732,7 +732,7 @@ def commonScalacOptions(scalaVersion: String) = "-language:implicitConversions", "-language:experimental.macros", "-unchecked", - "-Ywarn-dead-code", + //"-Ywarn-dead-code", "-Ywarn-numeric-widen", "-Ywarn-value-discard", "-Xfuture" From 164bc8116e113928c40fad4914b282c11dbcd90a Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 12 Nov 2018 13:05:30 -0800 Subject: [PATCH 13/87] Hmmmm --- core/src/main/scala/cats/data/Const.scala | 23 ++++++++++---- core/src/main/scala/cats/instances/all.scala | 8 ++++- core/src/main/scala/cats/instances/eq.scala | 25 +++++++++++++++ .../src/main/scala/cats/instances/equiv.scala | 31 +++++++++++++++++++ .../main/scala/cats/instances/function.scala | 29 ++++++++--------- .../src/main/scala/cats/instances/order.scala | 25 +++++++++++++++ .../main/scala/cats/instances/ordering.scala | 21 +++++++++++++ docs/src/main/tut/typeclasses/decideable.md | 31 +++++++++++++++++++ .../main/scala/cats/laws/DecideableLaws.scala | 19 ++++++------ .../laws/discipline/DecideableTests.scala | 31 ++++++++++--------- 10 files changed, 198 insertions(+), 45 deletions(-) diff --git a/core/src/main/scala/cats/data/Const.scala b/core/src/main/scala/cats/data/Const.scala index f811f854e0..4844394170 100644 --- a/core/src/main/scala/cats/data/Const.scala +++ b/core/src/main/scala/cats/data/Const.scala @@ -35,7 +35,7 @@ final case class Const[A, B](getConst: A) { s"Const(${A.show(getConst)})" } -object Const extends ConstInstances { +object Const extends ConstInstances with ConstInstancesBinCompat0 { def empty[A, B](implicit A: Monoid[A]): Const[A, B] = Const(A.empty) @@ -121,16 +121,13 @@ sealed abstract private[data] class ConstInstances extends ConstInstances0 { } sealed abstract private[data] class ConstInstances0 extends ConstInstances1 { - - implicit def catsDataDecideableForConst[D: Monoid]: Decideable[Const[D, ?]] = - new Decideable[Const[D, ?]] { + implicit def catsDataContravariantMonoidalForConst[D: Monoid]: ContravariantMonoidal[Const[D, ?]] = + new ContravariantMonoidal[Const[D, ?]] { override def unit = Const.empty[D, Unit] override def contramap[A, B](fa: Const[D, A])(f: B => A): Const[D, B] = fa.retag[B] override def product[A, B](fa: Const[D, A], fb: Const[D, B]): Const[D, (A, B)] = fa.retag[(A, B)].combine(fb.retag[(A, B)]) - def sum[A, B](fa: Const[D, A], fb: Const[D, B]): Const[D, Either[A, B]] = - fa.retag[Either[A, B]].combine(fb.retag[Either[A, B]]) } implicit def catsDataCommutativeApplicativeForConst[C]( @@ -181,6 +178,20 @@ sealed abstract private[data] class ConstInstances4 { new ConstContravariant[C] {} } +trait ConstInstancesBinCompat0 { + implicit def catsDataDecideableForConst[D: Monoid]: Decideable[Const[D, ?]] = + new Decideable[Const[D, ?]] { + override def unit = Const.empty[D, Unit] + override def contramap[A, B](fa: Const[D, A])(f: B => A): Const[D, B] = + fa.retag[B] + override def product[A, B](fa: Const[D, A], fb: Const[D, B]): Const[D, (A, B)] = + fa.retag[(A, B)].combine(fb.retag[(A, B)]) + def sum[A, B](fa: Const[D, A], fb: Const[D, B]): Const[D, Either[A, B]] = + fa.retag[Either[A, B]].combine(fb.retag[Either[A, B]]) + } + +} + sealed private[data] trait ConstFunctor[C] extends Functor[Const[C, ?]] { def map[A, B](fa: Const[C, A])(f: A => B): Const[C, B] = fa.retag[B] diff --git a/core/src/main/scala/cats/instances/all.scala b/core/src/main/scala/cats/instances/all.scala index 3cc7339d9d..32849aabfe 100644 --- a/core/src/main/scala/cats/instances/all.scala +++ b/core/src/main/scala/cats/instances/all.scala @@ -33,7 +33,13 @@ trait AllInstances with UUIDInstances with VectorInstances -trait AllInstancesBinCompat0 extends FunctionInstancesBinCompat0 with Tuple2InstancesBinCompat0 +trait AllInstancesBinCompat0 + extends FunctionInstancesBinCompat0 + with Tuple2InstancesBinCompat0 + with EqInstancesBinCompat0 + with EquivInstancesBinCompat0 + with OrderInstancesBinCompat0 + with OrderingInstancesBinCompat0 trait AllInstancesBinCompat1 extends OptionInstancesBinCompat0 diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index 38cc3a3062..c89d6cf7b8 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -5,6 +5,31 @@ import cats.instances.either._ import cats.syntax.apply._ trait EqInstances extends kernel.instances.EqInstances { + implicit val catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = + new ContravariantMonoidal[Eq] { + + /** + * Defaults to the trivial equivalence relation + * contracting the type to a point + */ + def unit: Eq[Unit] = Eq.allEqual + + /** Derive an `Eq` for `B` given an `Eq[A]` and a function `B => A`. + * + * Note: resulting instances are law-abiding only when the functions used are injective (represent a one-to-one mapping) + */ + def contramap[A, B](fa: Eq[A])(f: B => A): Eq[B] = + Eq.by(f)(fa) + + def product[A, B](fa: Eq[A], fb: Eq[B]): Eq[(A, B)] = + Eq.instance { (left, right) => + fa.eqv(left._1, right._1) && fb.eqv(left._2, right._2) + } + } + +} + +trait EqInstancesBinCompat0 { implicit val catsDecideableForEq: Decideable[Eq] = new Decideable[Eq] { diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index e029017969..9514c1fd0f 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -5,6 +5,36 @@ import cats.instances.either._ import cats.syntax.apply._ trait EquivInstances { + implicit val catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = + new ContravariantMonoidal[Equiv] { + + /** + * Defaults to trivially contracting the type + * to a point + */ + def unit: Equiv[Unit] = new Equiv[Unit] { + def equiv(x: Unit, y: Unit): Boolean = true + } + + /** Derive an `Equiv` for `B` given an `Equiv[A]` and a function `B => A`. + * + * Note: resulting instances are law-abiding only when the functions used are injective (represent a one-to-one mapping) + */ + def contramap[A, B](fa: Equiv[A])(f: B => A): Equiv[B] = + new Equiv[B] { + def equiv(l: B, r: B): Boolean = + fa.equiv(f(l), f(r)) + } + + def product[A, B](fa: Equiv[A], fb: Equiv[B]): Equiv[(A, B)] = + new Equiv[(A, B)] { + def equiv(l: (A, B), r: (A, B)): Boolean = + fa.equiv(l._1, r._1) && fb.equiv(l._2, r._2) + } + } +} + +trait EquivInstancesBinCompat0 { implicit val catsDecideableForEquiv: Decideable[Equiv] = new Decideable[Equiv] { @@ -44,4 +74,5 @@ trait EquivInstances { else false } } + } diff --git a/core/src/main/scala/cats/instances/function.scala b/core/src/main/scala/cats/instances/function.scala index 1d4ae0d9e2..28921a8d1c 100644 --- a/core/src/main/scala/cats/instances/function.scala +++ b/core/src/main/scala/cats/instances/function.scala @@ -58,6 +58,21 @@ trait FunctionInstancesBinCompat0 { Deferred(() => cachedFa) } } + + implicit def catsStdDecideableForPredicate: Decideable[? => Boolean] = + new Decideable[? => Boolean] { + def empty[A]: A => Boolean = Function.const(false) + def unit: Unit => Boolean = Function.const(true) + def contramap[A, B](fa: A => Boolean)(f: B => A): B => Boolean = + fa.compose(f) + def product[A, B](fa: A => Boolean, fb: B => Boolean): ((A, B)) => Boolean = + (ab: (A, B)) => + ab match { + case (a, b) => fa(a) && fb(b) + } + def sum[A, B](fa: A => Boolean, fb: B => Boolean): Either[A, B] => Boolean = + either => either.fold(fa, fb) + } } sealed private[instances] trait Function0Instances extends Function0Instances0 { @@ -97,20 +112,6 @@ sealed private[instances] trait Function0Instances0 { } sealed private[instances] trait Function1Instances extends Function1Instances0 { - implicit def catsStdDecideableForPredicate: Decideable[? => Boolean] = - new Decideable[? => Boolean] { - def empty[A]: A => Boolean = Function.const(false) - def unit: Unit => Boolean = Function.const(true) - def contramap[A, B](fa: A => Boolean)(f: B => A): B => Boolean = - fa.compose(f) - def product[A, B](fa: A => Boolean, fb: B => Boolean): ((A, B)) => Boolean = - (ab: (A, B)) => - ab match { - case (a, b) => fa(a) && fb(b) - } - def sum[A, B](fa: A => Boolean, fb: B => Boolean): Either[A, B] => Boolean = - either => either.fold(fa, fb) - } implicit def catsStdMonadForFunction1[T1]: Monad[T1 => ?] = new Monad[T1 => ?] { diff --git a/core/src/main/scala/cats/instances/order.scala b/core/src/main/scala/cats/instances/order.scala index 9d5f83eec0..9211463f90 100644 --- a/core/src/main/scala/cats/instances/order.scala +++ b/core/src/main/scala/cats/instances/order.scala @@ -6,7 +6,32 @@ import cats.syntax.apply._ import cats.kernel.instances.unit._ trait OrderInstances extends kernel.instances.OrderInstances { + implicit val catsContravariantMonoidalForOrder: ContravariantMonoidal[Order] = + new ContravariantMonoidal[Order] { + /** + * Provides trivial order + */ + def unit: Order[Unit] = Order[Unit] + + /** Derive an `Order` for `B` given an `Order[A]` and a function `B => A`. + * + * Note: resulting instances are law-abiding only when the functions used are injective (represent a one-to-one mapping) + */ + def contramap[A, B](fa: Order[A])(f: B => A): Order[B] = + Order.by(f)(fa) + + def product[A, B](fa: Order[A], fb: Order[B]): Order[(A, B)] = + new Order[(A, B)] { + def compare(x: (A, B), y: (A, B)): Int = { + val z = fa.compare(x._1, y._1) + if (z == 0) fb.compare(x._2, y._2) else z + } + } + } +} + +trait OrderInstancesBinCompat0 { implicit val catsDecideableForOrder: Decideable[Order] = new Decideable[Order] { diff --git a/core/src/main/scala/cats/instances/ordering.scala b/core/src/main/scala/cats/instances/ordering.scala index 124c239d8a..a0835ca301 100644 --- a/core/src/main/scala/cats/instances/ordering.scala +++ b/core/src/main/scala/cats/instances/ordering.scala @@ -6,6 +6,26 @@ import cats.syntax.apply._ import cats.kernel.instances.unit._ trait OrderingInstances { + implicit val catsContravariantMonoidalForOrdering: ContravariantMonoidal[Ordering] = + new ContravariantMonoidal[Ordering] { + + /** + * Note: resulting instances are law-abiding only when the functions used are injective (represent a one-to-one mapping) + */ + def unit: Ordering[Unit] = Order[Unit].toOrdering + + def contramap[A, B](fa: Ordering[A])(f: B => A): Ordering[B] = fa.on(f) + + def product[A, B](fa: Ordering[A], fb: Ordering[B]): Ordering[(A, B)] = + new Ordering[(A, B)] { + def compare(x: (A, B), y: (A, B)): Int = { + val z = fa.compare(x._1, y._1) + if (z == 0) fb.compare(x._2, y._2) else z + } + } + } +} +trait OrderingInstancesBinCompat0 { implicit val catsDecideableForOrdering: Decideable[Ordering] = new Decideable[Ordering] { @@ -36,4 +56,5 @@ trait OrderingInstances { else -1 } } + } diff --git a/docs/src/main/tut/typeclasses/decideable.md b/docs/src/main/tut/typeclasses/decideable.md index f0c7abfe72..b5194d437e 100644 --- a/docs/src/main/tut/typeclasses/decideable.md +++ b/docs/src/main/tut/typeclasses/decideable.md @@ -28,3 +28,34 @@ trait Decideable[F[_]] extends ContravariantMonoidal[F] { In other words, if we have two contexts `F[A]` and `F[B]` and we have a procedure `C => Either[A, B]` that could produce either an A or a B depending on the input, we have a way to produce a context `F[C]`. The classic example of a `Decideable` is that of predicates `A => Boolean`, leaning on the fact that both `&&` and `^` are valid monoids on `Boolean`. + +We can write the instance as: + +```tut:silent +implicit val decideableForPredicates = new Decideable[? => Boolean] { + def empty[A]: A => Boolean = Function.const(false) + def unit: Unit => Boolean = Function.const(true) + def contramap[A, B](fa: A => Boolean)(f: B => A): B => Boolean = + fa.compose(f) + def product[A, B](fa: A => Boolean, fb: B => Boolean): ((A, B)) => Boolean = + (ab: (A, B)) => + ab match { + case (a, b) => fa(a) && fb(b) + } + def sum[A, B](fa: A => Boolean, fb: B => Boolean): Either[A, B] => Boolean = + either => either.fold(fa, fb) +} +``` + +This can be used to combine predicates over both coproducts and products. + +```tut +def isEven(i: Int): Boolean = i % 2 == 0 +def isDivisibleByThree(l: Long): Boolean = l % 3 == 0 + +def isEvenRightOrDivisibleThreeLeft: Either[Int, Long] => Boolean = + Decideable[? => Boolean].sum(isEven, isDivisibleByThree) + +def isEvenRightAndDivisibleThreeLeft: (Int, Long) => Boolean = + Decideable[? => Boolean].product(isEven, isDivisibleByThree) +``` diff --git a/laws/src/main/scala/cats/laws/DecideableLaws.scala b/laws/src/main/scala/cats/laws/DecideableLaws.scala index 26fd273557..26594395c9 100644 --- a/laws/src/main/scala/cats/laws/DecideableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecideableLaws.scala @@ -7,18 +7,19 @@ trait DecideableLaws[F[_]] extends ContravariantMonoidalLaws[F] { def decideableDecideRightAbsorption[A](fa: F[A]): IsEq[F[A]] = (F.decide(F.trivial[A], fa))(Right.apply[A, A]) <-> fa - def decideableSumAssociativity[A, B, C](fa: F[A], fb: F[B], fc: F[C]): (F[Either[A, Either[B, C]]], F[Either[Either[A, B], C]]) = + def decideableSumAssociativity[A, B, C](fa: F[A], + fb: F[B], + fc: F[C]): (F[Either[A, Either[B, C]]], F[Either[Either[A, B], C]]) = (F.sum(fa, F.sum(fb, fc)), F.sum(F.sum(fa, fb), fc)) def decideableRightDistributivity[A, B, C](fa: F[A], fb: F[B], f: C => A, g: C => B): IsEq[F[Either[C, C]]] = - F.contramap(F.sum(fa, fb))( - (eit: Either[C, C]) => - eit.fold( - f andThen Left.apply, - g andThen Right.apply) - ) <-> F.sum( - F.contramap(fa)(f), - F.contramap(fb)(g)) + F.contramap(F.sum(fa, fb))( + (eit: Either[C, C]) => + eit.fold( + f.andThen(Left.apply), + g.andThen(Right.apply) + ) + ) <-> F.sum(F.contramap(fa)(f), F.contramap(fb)(g)) } object DecideableLaws { diff --git a/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala index 859fdb6604..6dd657a458 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecideableTests.scala @@ -9,20 +9,20 @@ trait DecideableTests[F[_]] extends ContravariantMonoidalTests[F] { def laws: DecideableLaws[F] def decideable[A: Arbitrary, B: Arbitrary, C: Arbitrary](implicit - arbFA: Arbitrary[F[A]], - arbFB: Arbitrary[F[B]], - arbFC: Arbitrary[F[C]], - CogenA: Cogen[A], - CogenB: Cogen[B], - CogenC: Cogen[C], - EqFA: Eq[F[A]], - EqFB: Eq[F[B]], - EqFC: Eq[F[C]], - EqFABC: Eq[F[(A, B, C)]], - EqCC: Eq[F[Either[C, C]]], - EqFEitABC: Eq[F[Either[Either[A, B], C]]], - iso: SemigroupalTests.Isomorphisms[F], - iso2: DecideableTests.Isomorphisms[F]): RuleSet = + arbFA: Arbitrary[F[A]], + arbFB: Arbitrary[F[B]], + arbFC: Arbitrary[F[C]], + CogenA: Cogen[A], + CogenB: Cogen[B], + CogenC: Cogen[C], + EqFA: Eq[F[A]], + EqFB: Eq[F[B]], + EqFC: Eq[F[C]], + EqFABC: Eq[F[(A, B, C)]], + EqCC: Eq[F[Either[C, C]]], + EqFEitABC: Eq[F[Either[Either[A, B], C]]], + iso: SemigroupalTests.Isomorphisms[F], + iso2: DecideableTests.Isomorphisms[F]): RuleSet = new RuleSet { val name = "decideable" val parents = Seq(contravariantMonoidal[A, B, C]) @@ -31,7 +31,8 @@ trait DecideableTests[F[_]] extends ContravariantMonoidalTests[F] { "decideable right absorption" -> forAll(laws.decideableDecideRightAbsorption[A] _), "decideable sum associativity" -> forAll( - (fa: F[A], fb: F[B], fc: F[C]) => iso2.associativity(laws.decideableSumAssociativity[A, B, C](fa, fb, fc))), + (fa: F[A], fb: F[B], fc: F[C]) => iso2.associativity(laws.decideableSumAssociativity[A, B, C](fa, fb, fc)) + ), "decideable right distributivity" -> forAll(laws.decideableRightDistributivity[A, B, C] _) ) From a14d7c4a207b004edf1dd663efeba0a4d1058f50 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 1 Jul 2019 23:38:32 -0700 Subject: [PATCH 14/87] Fix implicit conflict --- core/src/main/scala/cats/data/Const.scala | 6 +++--- tests/src/test/scala/cats/tests/ConstSuite.scala | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/cats/data/Const.scala b/core/src/main/scala/cats/data/Const.scala index 4844394170..30773e6c36 100644 --- a/core/src/main/scala/cats/data/Const.scala +++ b/core/src/main/scala/cats/data/Const.scala @@ -35,7 +35,7 @@ final case class Const[A, B](getConst: A) { s"Const(${A.show(getConst)})" } -object Const extends ConstInstances with ConstInstancesBinCompat0 { +object Const extends ConstInstances { def empty[A, B](implicit A: Monoid[A]): Const[A, B] = Const(A.empty) @@ -57,7 +57,7 @@ object Const extends ConstInstances with ConstInstancesBinCompat0 { def of[B]: OfPartiallyApplied[B] = new OfPartiallyApplied } -sealed abstract private[data] class ConstInstances extends ConstInstances0 { +sealed abstract private[data] class ConstInstances extends ConstInstancesBinCompat0 { implicit def catsDataOrderForConst[A: Order, B]: Order[Const[A, B]] = new Order[Const[A, B]] { def compare(x: Const[A, B], y: Const[A, B]): Int = x.compare(y) @@ -178,7 +178,7 @@ sealed abstract private[data] class ConstInstances4 { new ConstContravariant[C] {} } -trait ConstInstancesBinCompat0 { +trait ConstInstancesBinCompat0 extends ConstInstances0 { implicit def catsDataDecideableForConst[D: Monoid]: Decideable[Const[D, ?]] = new Decideable[Const[D, ?]] { override def unit = Const.empty[D, Unit] diff --git a/tests/src/test/scala/cats/tests/ConstSuite.scala b/tests/src/test/scala/cats/tests/ConstSuite.scala index 3b1a10d9b7..06179ba8a4 100644 --- a/tests/src/test/scala/cats/tests/ConstSuite.scala +++ b/tests/src/test/scala/cats/tests/ConstSuite.scala @@ -63,6 +63,10 @@ class ConstSuite extends CatsSuite { checkAll("ContravariantMonoidal[Const[String, ?]]", SerializableTests.serializable(ContravariantMonoidal[Const[String, ?]])) + checkAll("Const[String, Int", DecideableTests[Const[String, ?]].decideable[Int, Int, Int]) + checkAll("Decideable[Const[String, ?]]", + SerializableTests.serializable(Decideable[Const[String, ?]])) + checkAll("Const[?, ?]", BifoldableTests[Const].bifoldable[Int, Int, Int]) checkAll("Bifoldable[Const]", SerializableTests.serializable(Bifoldable[Const])) From 0a6fbf5a4b4cf3decefcd24d1d6de842ed9b3583 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 2 Jul 2019 09:02:29 -0700 Subject: [PATCH 15/87] Fix style and so forth --- core/src/main/scala/cats/instances/function.scala | 5 +---- tests/src/test/scala/cats/tests/ConstSuite.scala | 6 ++---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/core/src/main/scala/cats/instances/function.scala b/core/src/main/scala/cats/instances/function.scala index 28921a8d1c..778d47213d 100644 --- a/core/src/main/scala/cats/instances/function.scala +++ b/core/src/main/scala/cats/instances/function.scala @@ -1,7 +1,6 @@ package cats package instances -import cats.Contravariant import cats.arrow.{ArrowChoice, Category, CommutativeArrow} import annotation.tailrec @@ -65,9 +64,7 @@ trait FunctionInstancesBinCompat0 { def unit: Unit => Boolean = Function.const(true) def contramap[A, B](fa: A => Boolean)(f: B => A): B => Boolean = fa.compose(f) - def product[A, B](fa: A => Boolean, fb: B => Boolean): ((A, B)) => Boolean = - (ab: (A, B)) => - ab match { + def product[A, B](fa: A => Boolean, fb: B => Boolean): ((A, B)) => Boolean = { case (a, b) => fa(a) && fb(b) } def sum[A, B](fa: A => Boolean, fb: B => Boolean): Either[A, B] => Boolean = diff --git a/tests/src/test/scala/cats/tests/ConstSuite.scala b/tests/src/test/scala/cats/tests/ConstSuite.scala index 06179ba8a4..132e001dbe 100644 --- a/tests/src/test/scala/cats/tests/ConstSuite.scala +++ b/tests/src/test/scala/cats/tests/ConstSuite.scala @@ -60,12 +60,10 @@ class ConstSuite extends CatsSuite { checkAll("Contravariant[Const[String, ?]]", SerializableTests.serializable(Contravariant[Const[String, ?]])) checkAll("Const[String, Int]", ContravariantMonoidalTests[Const[String, ?]].contravariantMonoidal[Int, Int, Int]) - checkAll("ContravariantMonoidal[Const[String, ?]]", - SerializableTests.serializable(ContravariantMonoidal[Const[String, ?]])) + checkAll("ContravariantMonoidal[Const[String, ?]]", SerializableTests.serializable(ContravariantMonoidal[Const[String, ?]])) checkAll("Const[String, Int", DecideableTests[Const[String, ?]].decideable[Int, Int, Int]) - checkAll("Decideable[Const[String, ?]]", - SerializableTests.serializable(Decideable[Const[String, ?]])) + checkAll("Decideable[Const[String, ?]]", SerializableTests.serializable(Decideable[Const[String, ?]])) checkAll("Const[?, ?]", BifoldableTests[Const].bifoldable[Int, Int, Int]) checkAll("Bifoldable[Const]", SerializableTests.serializable(Bifoldable[Const])) From 5b5f04be6761a772114cc23fce23ab8f15d7576e Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 2 Jul 2019 14:07:16 -0700 Subject: [PATCH 16/87] Fix everything but MIMA --- core/src/main/scala/cats/data/OptionT.scala | 2 +- core/src/main/scala/cats/data/WriterT.scala | 2 +- core/src/main/scala/cats/instances/function.scala | 4 ++-- laws/src/main/scala/cats/laws/DecideableLaws.scala | 12 +++++++----- tests/src/test/scala/cats/tests/ConstSuite.scala | 3 ++- tests/src/test/scala/cats/tests/EqSuite.scala | 1 - tests/src/test/scala/cats/tests/KleisliSuite.scala | 7 ++++--- tests/src/test/scala/cats/tests/OpSuite.scala | 3 ++- tests/src/test/scala/cats/tests/OrderSuite.scala | 5 ++--- tests/src/test/scala/cats/tests/OrderingSuite.scala | 1 - 10 files changed, 21 insertions(+), 19 deletions(-) diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index be49294698..62fe990118 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -403,7 +403,7 @@ private trait OptionTDecideable[F[_]] extends Decideable[OptionT[F, ?]] with Opt case Some(Right(b)) => Right(Option(b)) case Some(Left(a)) => Left(Option(a)) case None => Left(None) - } + } ) ) } diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index af4e9c7710..a698bde66d 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -489,7 +489,7 @@ sealed private[data] trait WriterTDecideable[F[_], L] e match { case (l, Right(b)) => Right((l, b)) case (l, Left(a)) => Left((l, a)) - } + } ) ) } diff --git a/core/src/main/scala/cats/instances/function.scala b/core/src/main/scala/cats/instances/function.scala index bf3c9a8ddf..d5e48b8993 100644 --- a/core/src/main/scala/cats/instances/function.scala +++ b/core/src/main/scala/cats/instances/function.scala @@ -66,8 +66,8 @@ trait FunctionInstancesBinCompat0 { def contramap[A, B](fa: A => Boolean)(f: B => A): B => Boolean = fa.compose(f) def product[A, B](fa: A => Boolean, fb: B => Boolean): ((A, B)) => Boolean = { - case (a, b) => fa(a) && fb(b) - } + case (a, b) => fa(a) && fb(b) + } def sum[A, B](fa: A => Boolean, fb: B => Boolean): Either[A, B] => Boolean = either => either.fold(fa, fb) } diff --git a/laws/src/main/scala/cats/laws/DecideableLaws.scala b/laws/src/main/scala/cats/laws/DecideableLaws.scala index 26594395c9..9706c8ea9b 100644 --- a/laws/src/main/scala/cats/laws/DecideableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecideableLaws.scala @@ -5,11 +5,13 @@ trait DecideableLaws[F[_]] extends ContravariantMonoidalLaws[F] { implicit override def F: Decideable[F] def decideableDecideRightAbsorption[A](fa: F[A]): IsEq[F[A]] = - (F.decide(F.trivial[A], fa))(Right.apply[A, A]) <-> fa + F.decide(F.trivial[A], fa)(Right.apply[A, A]) <-> fa - def decideableSumAssociativity[A, B, C](fa: F[A], - fb: F[B], - fc: F[C]): (F[Either[A, Either[B, C]]], F[Either[Either[A, B], C]]) = + def decideableSumAssociativity[A, B, C]( + fa: F[A], + fb: F[B], + fc: F[C] + ): (F[Either[A, Either[B, C]]], F[Either[Either[A, B], C]]) = (F.sum(fa, F.sum(fb, fc)), F.sum(F.sum(fa, fb), fc)) def decideableRightDistributivity[A, B, C](fa: F[A], fb: F[B], f: C => A, g: C => B): IsEq[F[Either[C, C]]] = @@ -18,7 +20,7 @@ trait DecideableLaws[F[_]] extends ContravariantMonoidalLaws[F] { eit.fold( f.andThen(Left.apply), g.andThen(Right.apply) - ) + ) ) <-> F.sum(F.contramap(fa)(f), F.contramap(fb)(g)) } diff --git a/tests/src/test/scala/cats/tests/ConstSuite.scala b/tests/src/test/scala/cats/tests/ConstSuite.scala index 503a461b50..56d2a72976 100644 --- a/tests/src/test/scala/cats/tests/ConstSuite.scala +++ b/tests/src/test/scala/cats/tests/ConstSuite.scala @@ -69,7 +69,8 @@ class ConstSuite extends CatsSuite { checkAll("Contravariant[Const[String, ?]]", SerializableTests.serializable(Contravariant[Const[String, ?]])) checkAll("Const[String, Int]", ContravariantMonoidalTests[Const[String, ?]].contravariantMonoidal[Int, Int, Int]) - checkAll("ContravariantMonoidal[Const[String, ?]]", SerializableTests.serializable(ContravariantMonoidal[Const[String, ?]])) + checkAll("ContravariantMonoidal[Const[String, ?]]", + SerializableTests.serializable(ContravariantMonoidal[Const[String, ?]])) checkAll("Const[String, Int", DecideableTests[Const[String, ?]].decideable[Int, Int, Int]) checkAll("Decideable[Const[String, ?]]", SerializableTests.serializable(Decideable[Const[String, ?]])) diff --git a/tests/src/test/scala/cats/tests/EqSuite.scala b/tests/src/test/scala/cats/tests/EqSuite.scala index b43868c20d..0e57c0ceea 100644 --- a/tests/src/test/scala/cats/tests/EqSuite.scala +++ b/tests/src/test/scala/cats/tests/EqSuite.scala @@ -5,7 +5,6 @@ import cats.laws.discipline.arbitrary._ import cats.laws.discipline._ import cats.laws.discipline.eq._ - class EqSuite extends CatsSuite { Invariant[Eq] Contravariant[Eq] diff --git a/tests/src/test/scala/cats/tests/KleisliSuite.scala b/tests/src/test/scala/cats/tests/KleisliSuite.scala index 4089623554..329916c6eb 100644 --- a/tests/src/test/scala/cats/tests/KleisliSuite.scala +++ b/tests/src/test/scala/cats/tests/KleisliSuite.scala @@ -94,7 +94,8 @@ class KleisliSuite extends CatsSuite { Kleisli.catsDataDecideableForKleisli[Const[String, ?], Int] checkAll("Kleisli[Const[String, ?], Int, Int]", DecideableTests[Kleisli[Const[String, ?], MiniInt, ?]].decideable[Int, Int, Int]) - checkAll("Decideable[Kleisli[Option, Int, ?]]", + checkAll( + "Decideable[Kleisli[Option, Int, ?]]", SerializableTests.serializable[Decideable[Kleisli[Const[String, ?], Int, ?]]](catsDataDecideableForKleisli) ) } @@ -103,9 +104,9 @@ class KleisliSuite extends CatsSuite { implicit val catsDataContravariantMonoidalForKleisli = Kleisli.catsDataContravariantMonoidalForKleisli[Const[String, ?], Int] checkAll("Kleisli[Const[String, ?], MiniInt, ?]", - ContravariantMonoidalTests[Kleisli[Const[String, ?], MiniInt, ?]].contravariantMonoidal[Int, Int, Int]) + ContravariantMonoidalTests[Kleisli[Const[String, ?], MiniInt, ?]].contravariantMonoidal[Int, Int, Int]) checkAll("ContravariantMonoidal[Kleisli[Option, Int, ?]]", - SerializableTests.serializable(ContravariantMonoidal[Kleisli[Const[String, ?], Int, ?]])) + SerializableTests.serializable(ContravariantMonoidal[Kleisli[Const[String, ?], Int, ?]])) } checkAll("Kleisli[Option, MiniInt, Int]", ApplicativeTests[Kleisli[Option, MiniInt, ?]].applicative[Int, Int, Int]) diff --git a/tests/src/test/scala/cats/tests/OpSuite.scala b/tests/src/test/scala/cats/tests/OpSuite.scala index bafa77c786..c09493cae6 100644 --- a/tests/src/test/scala/cats/tests/OpSuite.scala +++ b/tests/src/test/scala/cats/tests/OpSuite.scala @@ -39,7 +39,8 @@ class OpSuite extends CatsSuite { { implicit val catsDataContravariantForOp = Op.catsDataContravariantForOp[Function1, Unit] - checkAll("Op[Function1, Unit, ?]", ContravariantTests[Op[Function1, Unit, ?]].contravariant[MiniInt, MiniInt, MiniInt]) + checkAll("Op[Function1, Unit, ?]", + ContravariantTests[Op[Function1, Unit, ?]].contravariant[MiniInt, MiniInt, MiniInt]) checkAll("Contravariant[Op[Function1, Unit, ?]]", SerializableTests.serializable(Contravariant[Op[Function1, Int, ?]])) diff --git a/tests/src/test/scala/cats/tests/OrderSuite.scala b/tests/src/test/scala/cats/tests/OrderSuite.scala index 606dc06ac1..9d61b43527 100644 --- a/tests/src/test/scala/cats/tests/OrderSuite.scala +++ b/tests/src/test/scala/cats/tests/OrderSuite.scala @@ -1,12 +1,11 @@ package cats package tests -import Helpers.Ord import cats.kernel.laws.discipline.{OrderTests, SerializableTests} -import cats.laws.discipline.DecideableTests -import cats.laws.discipline.{ContravariantMonoidalTests, MiniInt} +import cats.laws.discipline.{DecideableTests, MiniInt} import cats.laws.discipline.arbitrary._ import cats.laws.discipline.eq._ +import cats.tests.Helpers.Ord class OrderSuite extends CatsSuite { { diff --git a/tests/src/test/scala/cats/tests/OrderingSuite.scala b/tests/src/test/scala/cats/tests/OrderingSuite.scala index a4e65b2d43..b0d87cb733 100644 --- a/tests/src/test/scala/cats/tests/OrderingSuite.scala +++ b/tests/src/test/scala/cats/tests/OrderingSuite.scala @@ -14,7 +14,6 @@ class OrderingSuite extends CatsSuite { ContravariantMonoidal[Ordering] Decideable[Ordering] - checkAll("Contravariant[Ordering]", ContravariantTests[Ordering].contravariant[MiniInt, Int, Boolean]) checkAll("Semigroupal[Ordering]", SemigroupalTests[Ordering].semigroupal[MiniInt, Boolean, Boolean]) checkAll("ContravariantMonoidal[Ordering]", From 45fe0c481fe9d9213f83c92895df5ffc178b0f3a Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 20 Jul 2020 17:57:29 -0700 Subject: [PATCH 17/87] Format and fix OptionT instance --- core/src/main/scala/cats/ContravariantMonoidal.scala | 2 +- core/src/main/scala/cats/Decidable.scala | 3 +-- core/src/main/scala/cats/data/Op.scala | 1 - core/src/main/scala/cats/data/OptionT.scala | 11 +++++------ core/src/main/scala/cats/instances/function.scala | 2 +- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/core/src/main/scala/cats/ContravariantMonoidal.scala b/core/src/main/scala/cats/ContravariantMonoidal.scala index 6889b9657e..43abf2d69e 100644 --- a/core/src/main/scala/cats/ContravariantMonoidal.scala +++ b/core/src/main/scala/cats/ContravariantMonoidal.scala @@ -21,7 +21,7 @@ import scala.annotation.implicitNotFound * the diagonal */ def trivial[A]: F[A] = contramap(unit)(_ => ()) - + def conquer[A]: F[A] = trivial[A] } object ContravariantMonoidal extends SemigroupalArityFunctions { def monoid[F[_], A](implicit f: ContravariantMonoidal[F]): Monoid[F[A]] = diff --git a/core/src/main/scala/cats/Decidable.scala b/core/src/main/scala/cats/Decidable.scala index 9e1ea2a336..08a88465c9 100644 --- a/core/src/main/scala/cats/Decidable.scala +++ b/core/src/main/scala/cats/Decidable.scala @@ -24,8 +24,7 @@ import scala.annotation.implicitNotFound def decide[A, B, C](fa: F[A], fb: F[B])(f: C => Either[A, B]): F[C] = contramap(sum(fa, fb))(f) - def chosen[B, C](fb: F[B], fc: F[C]): F[Either[B, C]] = - decide(fb, fc)(identity[Either[B, C]]) + def chosen[B, C](fb: F[B], fc: F[C]): F[Either[B, C]] = sum(fb, fc) def lose[A](f: A => INothing): F[A] = contramap[INothing, A](zero)(f) def zero[A]: F[INothing] } diff --git a/core/src/main/scala/cats/data/Op.scala b/core/src/main/scala/cats/data/Op.scala index 38ed8f4001..8079cfcb28 100644 --- a/core/src/main/scala/cats/data/Op.scala +++ b/core/src/main/scala/cats/data/Op.scala @@ -73,7 +73,6 @@ private[data] trait OpDecidable[Arr[_, _], R] extends Decidable[Op[Arr, R, ?]] w def sum[A, B](fa: Op[Arr, R, A], fb: Op[Arr, R, B]): Op[Arr, R, Either[A, B]] = Op(Arr.choice(fa.run, fb.run)) - // FIXME: Dicey. This instance maybe should not exist unless we get Ring constraints override def zero[A]: Op[Arr, R, INothing] = Op(Arr.lift(INothing.absurd)) } diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index da08b66913..abbaeea411 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -502,14 +502,13 @@ private trait OptionTDecidable[F[_]] extends Decidable[OptionT[F, *]] with Optio def sum[A, B](fa: OptionT[F, A], fb: OptionT[F, B]): OptionT[F, Either[A, B]] = OptionT( F.decide(fa.value, fb.value)({ - case Some(Right(b)) => Right(Option(b)) - case Some(Left(a)) => Left(Option(a)) - case None => Left(None) - }) + case Some(Right(b)) => Right(Option(b)) + case Some(Left(a)) => Left(Option(a)) + case None => Left(None) + }) ) - // FIXME: Can this instance be made? - override def zero[A]: OptionT[F, INothing] = ??? + override def zero[A]: OptionT[F, INothing] = OptionT(F.trivial[Option[INothing]]) } private trait OptionTContravariantMonoidal[F[_]] extends ContravariantMonoidal[OptionT[F, *]] { diff --git a/core/src/main/scala/cats/instances/function.scala b/core/src/main/scala/cats/instances/function.scala index db256a6863..e4f8e89fa4 100644 --- a/core/src/main/scala/cats/instances/function.scala +++ b/core/src/main/scala/cats/instances/function.scala @@ -65,7 +65,7 @@ private[instances] trait FunctionInstancesBinCompat0 { def contramap[A, B](fa: A => Boolean)(f: B => A): B => Boolean = fa.compose(f) def product[A, B](fa: A => Boolean, fb: B => Boolean): ((A, B)) => Boolean = { - case (a, b) => fa(a)|| fb(b) + case (a, b) => fa(a) || fb(b) } def sum[A, B](fa: A => Boolean, fb: B => Boolean): Either[A, B] => Boolean = either => either.fold(fa, fb) From f3ce9ec4948b7ad7efc55156785a56648802770f Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 20 Jul 2020 18:07:28 -0700 Subject: [PATCH 18/87] More lintings --- .../test/scala/cats/tests/FunctionSuite.scala | 31 +++++++++++++++++-- .../src/test/scala/cats/tests/IdTSuite.scala | 4 +-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/tests/src/test/scala/cats/tests/FunctionSuite.scala b/tests/src/test/scala/cats/tests/FunctionSuite.scala index 57966eaab4..f0b7511f0d 100644 --- a/tests/src/test/scala/cats/tests/FunctionSuite.scala +++ b/tests/src/test/scala/cats/tests/FunctionSuite.scala @@ -1,11 +1,38 @@ package cats.tests -import cats.{Applicative, Bimonad, Contravariant, ContravariantMonoidal, Decidable, Defer, Distributive, Endo, Id, Monad, MonoidK, Semigroupal} +import cats.{ + Applicative, + Bimonad, + Contravariant, + ContravariantMonoidal, + Decidable, + Defer, + Distributive, + Endo, + Id, + Monad, + MonoidK, + Semigroupal +} import cats.arrow.{ArrowChoice, Choice, CommutativeArrow} import cats.instances.function._ import cats.kernel._ import cats.kernel.laws.HashLaws -import cats.kernel.laws.discipline.{BandTests, BoundedSemilatticeTests, CommutativeGroupTests, CommutativeMonoidTests, CommutativeSemigroupTests, EqTests, GroupTests, MonoidTests, OrderTests, PartialOrderTests, SemigroupTests, SemilatticeTests, SerializableTests} +import cats.kernel.laws.discipline.{ + BandTests, + BoundedSemilatticeTests, + CommutativeGroupTests, + CommutativeMonoidTests, + CommutativeSemigroupTests, + EqTests, + GroupTests, + MonoidTests, + OrderTests, + PartialOrderTests, + SemigroupTests, + SemilatticeTests, + SerializableTests +} import cats.laws.discipline._ import cats.laws.discipline.SemigroupalTests.Isomorphisms import cats.laws.discipline.eq._ diff --git a/tests/src/test/scala/cats/tests/IdTSuite.scala b/tests/src/test/scala/cats/tests/IdTSuite.scala index e4d7bfaafd..7b5ac55304 100644 --- a/tests/src/test/scala/cats/tests/IdTSuite.scala +++ b/tests/src/test/scala/cats/tests/IdTSuite.scala @@ -68,9 +68,7 @@ class IdTSuite extends CatsSuite { { implicit val coproductIso = DecidableTests.Isomorphisms.invariant[IdT[Const[String, ?], ?]] checkAll("IdT[Const[String, ?], ?]", DecidableTests[IdT[Const[String, ?], ?]].decidable[Int, Int, Int]) - checkAll("Decidable[IdT[Const[String, ?], ?]]", - SerializableTests.serializable(Decidable[IdT[Const[String, ?], ?]]) - ) + checkAll("Decidable[IdT[Const[String, ?], ?]]", SerializableTests.serializable(Decidable[IdT[Const[String, ?], ?]])) } { From 2d38c82b7bf5bfb19b1cbd458b0bd287934a7fd6 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 20 Jul 2020 18:32:50 -0700 Subject: [PATCH 19/87] Fix build settings --- build.sbt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.sbt b/build.sbt index 97b8e18beb..8e67f9e469 100644 --- a/build.sbt +++ b/build.sbt @@ -815,6 +815,9 @@ def commonScalacOptions(scalaVersion: String, isDotty: Boolean) = "UTF-8", "-feature", "-unchecked", + //"-Ywarn-dead-code", + "-Ywarn-numeric-widen", + "-Ywarn-value-discard", "-Xfatal-warnings", "-deprecation" ) ++ (if (priorTo2_13(scalaVersion)) From 26d812d1b58b3c5fd9fcab30ff4105ec7cf7bfdf Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 20 Jul 2020 18:42:14 -0700 Subject: [PATCH 20/87] Undo weird thing --- core/src/main/scala/cats/Invariant.scala | 2 +- core/src/main/scala/cats/Semigroupal.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/Invariant.scala b/core/src/main/scala/cats/Invariant.scala index a195359587..ddcd9f5c41 100644 --- a/core/src/main/scala/cats/Invariant.scala +++ b/core/src/main/scala/cats/Invariant.scala @@ -139,7 +139,7 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn implicit def catsContravariantMonoidalForPartialOrdering: ContravariantMonoidal[PartialOrdering] = cats.instances.partialOrdering.catsContravariantMonoidalForPartialOrdering implicit def catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = - cats.instances.eq.catsDecidableForEq + cats.instances.eq.catsContravariantMonoidalForEq implicit def catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = cats.instances.equiv.catsDecidableForEquiv implicit def catsContravariantForHash: Contravariant[Hash] = diff --git a/core/src/main/scala/cats/Semigroupal.scala b/core/src/main/scala/cats/Semigroupal.scala index 24e4ff1080..8a5b978acd 100644 --- a/core/src/main/scala/cats/Semigroupal.scala +++ b/core/src/main/scala/cats/Semigroupal.scala @@ -74,7 +74,7 @@ object Semigroupal extends ScalaVersionSpecificSemigroupalInstances with Semigro cats.instances.ordering.catsContravariantMonoidalForOrdering implicit val catsSemigroupalForPartialOrdering: Semigroupal[PartialOrdering] = cats.instances.partialOrdering.catsContravariantMonoidalForPartialOrdering - implicit val catsSemigroupalForEq: Semigroupal[Eq] = cats.instances.eq.catsDecidableForEq + implicit val catsSemigroupalForEq: Semigroupal[Eq] = cats.instances.eq.catsContravariantMonoidalForEq implicit val catsSemigroupalForEquiv: Semigroupal[Equiv] = cats.instances.equiv.catsDecidableForEquiv implicit val catsSemigroupalForMonoid: Semigroupal[Monoid] = From ce3f3800ee764edfc2dea7e5b37a4d916061ea62 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 20 Jul 2020 18:56:06 -0700 Subject: [PATCH 21/87] Double down --- core/src/main/scala/cats/Invariant.scala | 2 +- core/src/main/scala/cats/Semigroupal.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/Invariant.scala b/core/src/main/scala/cats/Invariant.scala index ddcd9f5c41..e0de33a706 100644 --- a/core/src/main/scala/cats/Invariant.scala +++ b/core/src/main/scala/cats/Invariant.scala @@ -141,7 +141,7 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn implicit def catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = cats.instances.eq.catsContravariantMonoidalForEq implicit def catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = - cats.instances.equiv.catsDecidableForEquiv + cats.instances.equiv.catsContravariantMonoidalForEquiv implicit def catsContravariantForHash: Contravariant[Hash] = cats.instances.all.catsContravariantForHash implicit def catsInvariantMonoidalForSemigroup: InvariantMonoidal[Semigroup] = diff --git a/core/src/main/scala/cats/Semigroupal.scala b/core/src/main/scala/cats/Semigroupal.scala index 8a5b978acd..1da60fdbef 100644 --- a/core/src/main/scala/cats/Semigroupal.scala +++ b/core/src/main/scala/cats/Semigroupal.scala @@ -76,7 +76,7 @@ object Semigroupal extends ScalaVersionSpecificSemigroupalInstances with Semigro cats.instances.partialOrdering.catsContravariantMonoidalForPartialOrdering implicit val catsSemigroupalForEq: Semigroupal[Eq] = cats.instances.eq.catsContravariantMonoidalForEq implicit val catsSemigroupalForEquiv: Semigroupal[Equiv] = - cats.instances.equiv.catsDecidableForEquiv + cats.instances.equiv.catsContravariantMonoidalForEquiv implicit val catsSemigroupalForMonoid: Semigroupal[Monoid] = cats.instances.invariant.catsSemigroupalForMonoid implicit val catsSemigroupalForSemigroup: Semigroupal[Semigroup] = From 289588aac708dc803cbf13c28bf207bffb3664e7 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 20 Jul 2020 19:48:34 -0700 Subject: [PATCH 22/87] Try and get better cross-version compat --- core/src/main/scala/cats/instances/ordering.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/instances/ordering.scala b/core/src/main/scala/cats/instances/ordering.scala index 89cc7a779e..4384fdaa1d 100644 --- a/core/src/main/scala/cats/instances/ordering.scala +++ b/core/src/main/scala/cats/instances/ordering.scala @@ -50,10 +50,10 @@ trait OrderingInstancesBinCompat0 { def compare(x: Either[A, B], y: Either[A, B]): Int = if (x.isRight) if (y.isRight) - (x, y).mapN(fb.compare).right.get + (x, y).mapN(fb.compare).toOption.get else 1 else if (y.isLeft) - (x.swap, y.swap).mapN(fa.compare).right.get + (x.swap, y.swap).mapN(fa.compare).toOption.get else -1 } From f9d8f181c47b7b1e73beb255f85178bdd46dc78a Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 20 Jul 2020 20:35:56 -0700 Subject: [PATCH 23/87] And more so --- core/src/main/scala/cats/instances/eq.scala | 4 ++-- core/src/main/scala/cats/instances/equiv.scala | 4 ++-- core/src/main/scala/cats/instances/order.scala | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index ccfc045c74..c05456c4a8 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -59,10 +59,10 @@ trait EqInstancesBinCompat0 { Eq.instance { (left, right) => if (left.isRight) if (right.isRight) - (left, right).mapN(fb.eqv).right.get + (left, right).mapN(fb.eqv).toOption.get else false else if (right.isLeft) - (left.swap, right.swap).mapN(fa.eqv).right.get + (left.swap, right.swap).mapN(fa.eqv).toOption.get else false } diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index 6145a84996..a8001bd4ed 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -72,10 +72,10 @@ trait EquivInstancesBinCompat0 { def equiv(x: Either[A, B], y: Either[A, B]): Boolean = if (x.isRight) if (y.isRight) - (x, y).mapN(fb.equiv).right.get + (x, y).mapN(fb.equiv).toOption.get else false else if (y.isLeft) - (x.swap, y.swap).mapN(fa.equiv).right.get + (x.swap, y.swap).mapN(fa.equiv).toOption.get else false } diff --git a/core/src/main/scala/cats/instances/order.scala b/core/src/main/scala/cats/instances/order.scala index c41df553bd..4e0b344ceb 100644 --- a/core/src/main/scala/cats/instances/order.scala +++ b/core/src/main/scala/cats/instances/order.scala @@ -63,10 +63,10 @@ trait OrderInstancesBinCompat0 { def compare(x: Either[A, B], y: Either[A, B]): Int = if (x.isRight) if (y.isRight) - (x, y).mapN(fb.compare).right.get + (x, y).mapN(fb.compare).toOption.get else 1 else if (y.isLeft) - (x.swap, y.swap).mapN(fa.compare).right.get + (x.swap, y.swap).mapN(fa.compare).toOption.get else -1 } From ec6920b76402e55c3ecc16f729d32e1650448879 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 21 Jul 2020 10:19:38 -0700 Subject: [PATCH 24/87] Fix some version specific instances --- core/src/main/scala/cats/Invariant.scala | 17 +++++++++-------- core/src/main/scala/cats/Semigroupal.scala | 8 ++++---- tests/src/test/scala/cats/tests/EqSuite.scala | 1 - .../src/test/scala/cats/tests/EquivSuite.scala | 1 - .../src/test/scala/cats/tests/OrderSuite.scala | 1 - .../test/scala/cats/tests/OrderingSuite.scala | 2 -- 6 files changed, 13 insertions(+), 17 deletions(-) diff --git a/core/src/main/scala/cats/Invariant.scala b/core/src/main/scala/cats/Invariant.scala index e0de33a706..2d62f904a5 100644 --- a/core/src/main/scala/cats/Invariant.scala +++ b/core/src/main/scala/cats/Invariant.scala @@ -130,18 +130,10 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn implicit def catsInstancesForTry: MonadError[Try, Throwable] with CoflatMap[Try] = cats.instances.try_.catsStdInstancesForTry - implicit def catsContravariantMonoidalForOrder: ContravariantMonoidal[Order] = - cats.instances.order.catsContravariantMonoidalForOrder implicit def catsContravariantMonoidalForPartialOrder: ContravariantMonoidal[PartialOrder] = cats.instances.partialOrder.catsContravariantMonoidalForPartialOrder - implicit def catsContravariantMonoidalForOrdering: ContravariantMonoidal[Ordering] = - cats.instances.ordering.catsContravariantMonoidalForOrdering implicit def catsContravariantMonoidalForPartialOrdering: ContravariantMonoidal[PartialOrdering] = cats.instances.partialOrdering.catsContravariantMonoidalForPartialOrdering - implicit def catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = - cats.instances.eq.catsContravariantMonoidalForEq - implicit def catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = - cats.instances.equiv.catsContravariantMonoidalForEquiv implicit def catsContravariantForHash: Contravariant[Hash] = cats.instances.all.catsContravariantForHash implicit def catsInvariantMonoidalForSemigroup: InvariantMonoidal[Semigroup] = @@ -151,6 +143,15 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn implicit def catsInvariantSemigroupalForMonoid: InvariantSemigroupal[Monoid] = cats.instances.invariant.catsSemigroupalForMonoid + implicit def catsDecidableForEquiv: Decidable[Equiv] = + cats.instances.equiv.catsDecidableForEquiv + implicit def catsDecidableForEq: Decidable[Eq] = + cats.instances.eq.catsDecidableForEq + implicit def catsDecidableForOrder: Decidable[Order] = + cats.instances.order.catsDecidableForOrder + implicit def catsDecidableForOrdering: Decidable[Ordering] = + cats.instances.ordering.catsDecidableForOrdering + implicit val catsInvariantMonoid: Invariant[Monoid] = new Invariant[Monoid] { def imap[A, B](fa: Monoid[A])(f: A => B)(g: B => A): Monoid[B] = diff --git a/core/src/main/scala/cats/Semigroupal.scala b/core/src/main/scala/cats/Semigroupal.scala index 1da60fdbef..3215ced9fb 100644 --- a/core/src/main/scala/cats/Semigroupal.scala +++ b/core/src/main/scala/cats/Semigroupal.scala @@ -67,16 +67,16 @@ object Semigroupal extends ScalaVersionSpecificSemigroupalInstances with Semigro implicit def catsSemigroupalForFunction0: Semigroupal[Function0] = cats.instances.function.catsStdBimonadForFunction0 - implicit val catsSemigroupalForOrder: Semigroupal[Order] = cats.instances.order.catsContravariantMonoidalForOrder + implicit val catsSemigroupalForOrder: Semigroupal[Order] = cats.instances.order.catsDecidableForOrder implicit val catsSemigroupalForPartialOrder: Semigroupal[PartialOrder] = cats.instances.partialOrder.catsContravariantMonoidalForPartialOrder implicit val catsSemigroupalForOrdering: Semigroupal[Ordering] = - cats.instances.ordering.catsContravariantMonoidalForOrdering + cats.instances.ordering.catsDecidableForOrdering implicit val catsSemigroupalForPartialOrdering: Semigroupal[PartialOrdering] = cats.instances.partialOrdering.catsContravariantMonoidalForPartialOrdering - implicit val catsSemigroupalForEq: Semigroupal[Eq] = cats.instances.eq.catsContravariantMonoidalForEq + implicit val catsSemigroupalForEq: Semigroupal[Eq] = cats.instances.eq.catsDecidableForEq implicit val catsSemigroupalForEquiv: Semigroupal[Equiv] = - cats.instances.equiv.catsContravariantMonoidalForEquiv + cats.instances.equiv.catsDecidableForEquiv implicit val catsSemigroupalForMonoid: Semigroupal[Monoid] = cats.instances.invariant.catsSemigroupalForMonoid implicit val catsSemigroupalForSemigroup: Semigroupal[Semigroup] = diff --git a/tests/src/test/scala/cats/tests/EqSuite.scala b/tests/src/test/scala/cats/tests/EqSuite.scala index 31898a4413..83866fc6ed 100644 --- a/tests/src/test/scala/cats/tests/EqSuite.scala +++ b/tests/src/test/scala/cats/tests/EqSuite.scala @@ -1,7 +1,6 @@ package cats.tests import cats.{Contravariant, ContravariantSemigroupal, Decidable, Eq, Invariant, Semigroupal} -import cats.instances.eq._ import cats.laws.discipline.arbitrary._ import cats.laws.discipline._ import cats.laws.discipline.eq._ diff --git a/tests/src/test/scala/cats/tests/EquivSuite.scala b/tests/src/test/scala/cats/tests/EquivSuite.scala index 872a2abc0a..761a82d6d0 100644 --- a/tests/src/test/scala/cats/tests/EquivSuite.scala +++ b/tests/src/test/scala/cats/tests/EquivSuite.scala @@ -1,7 +1,6 @@ package cats.tests import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal, Decidable, Invariant, Semigroupal} -import cats.instances.equiv._ import cats.laws.discipline.arbitrary._ import cats.laws.discipline._ import cats.laws.discipline.eq._ diff --git a/tests/src/test/scala/cats/tests/OrderSuite.scala b/tests/src/test/scala/cats/tests/OrderSuite.scala index 81dab3e15e..400ed7f5da 100644 --- a/tests/src/test/scala/cats/tests/OrderSuite.scala +++ b/tests/src/test/scala/cats/tests/OrderSuite.scala @@ -1,7 +1,6 @@ package cats.tests import cats.{Contravariant, ContravariantMonoidal, Decidable, Invariant} -import cats.instances.order._ import cats.kernel.{Order, PartialOrder} import cats.kernel.laws.discipline.{OrderTests, SerializableTests} import cats.laws.discipline.{DecidableTests, MiniInt} diff --git a/tests/src/test/scala/cats/tests/OrderingSuite.scala b/tests/src/test/scala/cats/tests/OrderingSuite.scala index 4a3f2256b0..20ac3700fb 100644 --- a/tests/src/test/scala/cats/tests/OrderingSuite.scala +++ b/tests/src/test/scala/cats/tests/OrderingSuite.scala @@ -1,13 +1,11 @@ package cats.tests import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal, Decidable, Invariant, Semigroupal} -import cats.instances.ordering._ import cats.laws.discipline.arbitrary._ import cats.laws.discipline._ import cats.laws.discipline.eq._ class OrderingSuite extends CatsSuite { - Invariant[Ordering] Contravariant[Ordering] Semigroupal[Ordering] From 4af7db2230b1e2f0850a45e55ff8d68c1dd08372 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 21 Jul 2020 10:51:10 -0700 Subject: [PATCH 25/87] Pretty weird stuff I guess --- core/src/main/scala/cats/instances/eq.scala | 38 +++++++++--------- .../src/main/scala/cats/instances/equiv.scala | 39 +++++++++---------- .../src/main/scala/cats/instances/order.scala | 38 +++++++++--------- .../main/scala/cats/instances/ordering.scala | 39 +++++++++---------- 4 files changed, 75 insertions(+), 79 deletions(-) diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index c05456c4a8..bce27688e6 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -6,9 +6,8 @@ import cats.instances.either._ import cats.syntax.apply._ trait EqInstances extends kernel.instances.EqInstances { - - implicit val catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = - new ContravariantMonoidal[Eq] { + implicit val catsDecidableForEq: Decidable[Eq] = + new Decidable[Eq] { /** * Defaults to the trivial equivalence relation @@ -28,13 +27,25 @@ trait EqInstances extends kernel.instances.EqInstances { Eq.instance { (left, right) => fa.eqv(left._1, right._1) && fb.eqv(left._2, right._2) } - } + def sum[A, B](fa: Eq[A], fb: Eq[B]): Eq[Either[A, B]] = + Eq.instance { (left, right) => + if (left.isRight) + if (right.isRight) + (left, right).mapN(fb.eqv).toOption.get + else false + else if (right.isLeft) + (left.swap, right.swap).mapN(fa.eqv).toOption.get + else false + } + + override def zero[A]: Eq[INothing] = Eq.allEqual[INothing] + } } -trait EqInstancesBinCompat0 { - implicit val catsDecidableForEq: Decidable[Eq] = - new Decidable[Eq] { +private [instances] trait EqInstancesBinCompat0 { + implicit val catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = + new ContravariantMonoidal[Eq] { /** * Defaults to the trivial equivalence relation @@ -54,18 +65,5 @@ trait EqInstancesBinCompat0 { Eq.instance { (left, right) => fa.eqv(left._1, right._1) && fb.eqv(left._2, right._2) } - - def sum[A, B](fa: Eq[A], fb: Eq[B]): Eq[Either[A, B]] = - Eq.instance { (left, right) => - if (left.isRight) - if (right.isRight) - (left, right).mapN(fb.eqv).toOption.get - else false - else if (right.isLeft) - (left.swap, right.swap).mapN(fa.eqv).toOption.get - else false - } - - override def zero[A]: Eq[INothing] = Eq.allEqual[INothing] } } diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index a8001bd4ed..6e71783d58 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -6,8 +6,8 @@ import cats.instances.either._ import cats.syntax.apply._ trait EquivInstances { - implicit val catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = - new ContravariantMonoidal[Equiv] { + implicit val catsDecidableForEquiv: Decidable[Equiv] = + new Decidable[Equiv] { /** * Defaults to trivially contracting the type @@ -34,12 +34,26 @@ trait EquivInstances { def equiv(l: (A, B), r: (A, B)): Boolean = fa.equiv(l._1, r._1) && fb.equiv(l._2, r._2) } + + def sum[A, B](fa: Equiv[A], fb: Equiv[B]): Equiv[Either[A, B]] = + new Equiv[Either[A, B]] { + def equiv(x: Either[A, B], y: Either[A, B]): Boolean = + if (x.isRight) + if (y.isRight) + (x, y).mapN(fb.equiv).toOption.get + else false + else if (y.isLeft) + (x.swap, y.swap).mapN(fa.equiv).toOption.get + else false + } + + override def zero[A]: Equiv[INothing] = Equiv.by(_ => ()) } } -trait EquivInstancesBinCompat0 { - implicit val catsDecidableForEquiv: Decidable[Equiv] = - new Decidable[Equiv] { +private [instances] trait EquivInstancesBinCompat0 { + implicit val catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = + new ContravariantMonoidal[Equiv] { /** * Defaults to trivially contracting the type @@ -66,20 +80,5 @@ trait EquivInstancesBinCompat0 { def equiv(l: (A, B), r: (A, B)): Boolean = fa.equiv(l._1, r._1) && fb.equiv(l._2, r._2) } - - def sum[A, B](fa: Equiv[A], fb: Equiv[B]): Equiv[Either[A, B]] = - new Equiv[Either[A, B]] { - def equiv(x: Either[A, B], y: Either[A, B]): Boolean = - if (x.isRight) - if (y.isRight) - (x, y).mapN(fb.equiv).toOption.get - else false - else if (y.isLeft) - (x.swap, y.swap).mapN(fa.equiv).toOption.get - else false - } - - override def zero[A]: Equiv[INothing] = Equiv.by(_ => ()) } - } diff --git a/core/src/main/scala/cats/instances/order.scala b/core/src/main/scala/cats/instances/order.scala index 4e0b344ceb..8878c71ec1 100644 --- a/core/src/main/scala/cats/instances/order.scala +++ b/core/src/main/scala/cats/instances/order.scala @@ -7,8 +7,8 @@ import cats.syntax.apply._ import cats.kernel.instances.unit._ trait OrderInstances extends kernel.instances.OrderInstances { - implicit val catsContravariantMonoidalForOrder: ContravariantMonoidal[Order] = - new ContravariantMonoidal[Order] { + implicit val catsDecidableForOrder: Decidable[Order] = + new Decidable[Order] { /** * Provides trivial order @@ -30,12 +30,26 @@ trait OrderInstances extends kernel.instances.OrderInstances { if (z == 0) fb.compare(x._2, y._2) else z } } + + def sum[A, B](fa: Order[A], fb: Order[B]): Order[Either[A, B]] = + new Order[Either[A, B]] { + def compare(x: Either[A, B], y: Either[A, B]): Int = + if (x.isRight) + if (y.isRight) + (x, y).mapN(fb.compare).toOption.get + else 1 + else if (y.isLeft) + (x.swap, y.swap).mapN(fa.compare).toOption.get + else -1 + } + + override def zero[A]: Order[INothing] = Order.by(_ => ()) } } -trait OrderInstancesBinCompat0 { - implicit val catsDecidableForOrder: Decidable[Order] = - new Decidable[Order] { +private [instances] trait OrderInstancesBinCompat0 { + implicit val catsContravariantMonoidalForOrder: ContravariantMonoidal[Order] = + new ContravariantMonoidal[Order] { /** * Provides trivial order @@ -57,19 +71,5 @@ trait OrderInstancesBinCompat0 { if (z == 0) fb.compare(x._2, y._2) else z } } - - def sum[A, B](fa: Order[A], fb: Order[B]): Order[Either[A, B]] = - new Order[Either[A, B]] { - def compare(x: Either[A, B], y: Either[A, B]): Int = - if (x.isRight) - if (y.isRight) - (x, y).mapN(fb.compare).toOption.get - else 1 - else if (y.isLeft) - (x.swap, y.swap).mapN(fa.compare).toOption.get - else -1 - } - - override def zero[A]: Order[INothing] = Order.by(_ => ()) } } diff --git a/core/src/main/scala/cats/instances/ordering.scala b/core/src/main/scala/cats/instances/ordering.scala index 4384fdaa1d..db00e8901d 100644 --- a/core/src/main/scala/cats/instances/ordering.scala +++ b/core/src/main/scala/cats/instances/ordering.scala @@ -7,26 +7,6 @@ import cats.syntax.apply._ import cats.kernel.instances.unit._ trait OrderingInstances { - implicit val catsContravariantMonoidalForOrdering: ContravariantMonoidal[Ordering] = - new ContravariantMonoidal[Ordering] { - - /** - * Note: resulting instances are law-abiding only when the functions used are injective (represent a one-to-one mapping) - */ - def unit: Ordering[Unit] = Order[Unit].toOrdering - - def contramap[A, B](fa: Ordering[A])(f: B => A): Ordering[B] = fa.on(f) - - def product[A, B](fa: Ordering[A], fb: Ordering[B]): Ordering[(A, B)] = - new Ordering[(A, B)] { - def compare(x: (A, B), y: (A, B)): Int = { - val z = fa.compare(x._1, y._1) - if (z == 0) fb.compare(x._2, y._2) else z - } - } - } -} -trait OrderingInstancesBinCompat0 { implicit val catsDecidableForOrdering: Decidable[Ordering] = new Decidable[Ordering] { @@ -59,5 +39,24 @@ trait OrderingInstancesBinCompat0 { override def zero[A]: Ordering[INothing] = Ordering.by(_ => ()) } +} +private [instances] trait OrderingInstancesBinCompat0 { + + implicit val catsContravariantMonoidalForOrdering: ContravariantMonoidal[Ordering] = + new ContravariantMonoidal[Ordering] { + /** + * Note: resulting instances are law-abiding only when the functions used are injective (represent a one-to-one mapping) + */ + def unit: Ordering[Unit] = Order[Unit].toOrdering + + def contramap[A, B](fa: Ordering[A])(f: B => A): Ordering[B] = fa.on(f) + def product[A, B](fa: Ordering[A], fb: Ordering[B]): Ordering[(A, B)] = + new Ordering[(A, B)] { + def compare(x: (A, B), y: (A, B)): Int = { + val z = fa.compare(x._1, y._1) + if (z == 0) fb.compare(x._2, y._2) else z + } + } + } } From 8a9930086a51472811c5b2aa4ae3e0d123948ae0 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 21 Jul 2020 11:43:45 -0700 Subject: [PATCH 26/87] Formatting --- core/src/main/scala/cats/instances/eq.scala | 2 +- core/src/main/scala/cats/instances/equiv.scala | 2 +- core/src/main/scala/cats/instances/order.scala | 2 +- core/src/main/scala/cats/instances/ordering.scala | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index bce27688e6..64206b4bbe 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -43,7 +43,7 @@ trait EqInstances extends kernel.instances.EqInstances { } } -private [instances] trait EqInstancesBinCompat0 { +private[instances] trait EqInstancesBinCompat0 { implicit val catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = new ContravariantMonoidal[Eq] { diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index 6e71783d58..a7f1555708 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -51,7 +51,7 @@ trait EquivInstances { } } -private [instances] trait EquivInstancesBinCompat0 { +private[instances] trait EquivInstancesBinCompat0 { implicit val catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = new ContravariantMonoidal[Equiv] { diff --git a/core/src/main/scala/cats/instances/order.scala b/core/src/main/scala/cats/instances/order.scala index 8878c71ec1..5367465b5a 100644 --- a/core/src/main/scala/cats/instances/order.scala +++ b/core/src/main/scala/cats/instances/order.scala @@ -47,7 +47,7 @@ trait OrderInstances extends kernel.instances.OrderInstances { } } -private [instances] trait OrderInstancesBinCompat0 { +private[instances] trait OrderInstancesBinCompat0 { implicit val catsContravariantMonoidalForOrder: ContravariantMonoidal[Order] = new ContravariantMonoidal[Order] { diff --git a/core/src/main/scala/cats/instances/ordering.scala b/core/src/main/scala/cats/instances/ordering.scala index db00e8901d..70aea44465 100644 --- a/core/src/main/scala/cats/instances/ordering.scala +++ b/core/src/main/scala/cats/instances/ordering.scala @@ -40,8 +40,7 @@ trait OrderingInstances { override def zero[A]: Ordering[INothing] = Ordering.by(_ => ()) } } -private [instances] trait OrderingInstancesBinCompat0 { - +private[instances] trait OrderingInstancesBinCompat0 { implicit val catsContravariantMonoidalForOrdering: ContravariantMonoidal[Ordering] = new ContravariantMonoidal[Ordering] { /** From a27b3917e91ce41f93e008b5b04357abe825e2b0 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 21 Jul 2020 11:49:33 -0700 Subject: [PATCH 27/87] Another linting --- core/src/main/scala/cats/instances/ordering.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/scala/cats/instances/ordering.scala b/core/src/main/scala/cats/instances/ordering.scala index 70aea44465..b2239839fc 100644 --- a/core/src/main/scala/cats/instances/ordering.scala +++ b/core/src/main/scala/cats/instances/ordering.scala @@ -43,6 +43,7 @@ trait OrderingInstances { private[instances] trait OrderingInstancesBinCompat0 { implicit val catsContravariantMonoidalForOrdering: ContravariantMonoidal[Ordering] = new ContravariantMonoidal[Ordering] { + /** * Note: resulting instances are law-abiding only when the functions used are injective (represent a one-to-one mapping) */ From 39e63958a41ab21881109809a56494ca051d4a56 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 21 Jul 2020 13:00:13 -0700 Subject: [PATCH 28/87] Fix tut probably and remove Const instance --- core/src/main/scala/cats/data/Const.scala | 18 +------------ docs/src/main/tut/typeclasses/decidable.md | 25 ++++++++++++------- .../test/scala/cats/tests/ConstSuite.scala | 3 --- 3 files changed, 17 insertions(+), 29 deletions(-) diff --git a/core/src/main/scala/cats/data/Const.scala b/core/src/main/scala/cats/data/Const.scala index 05fb8121f1..d16cbc3b40 100644 --- a/core/src/main/scala/cats/data/Const.scala +++ b/core/src/main/scala/cats/data/Const.scala @@ -56,7 +56,7 @@ object Const extends ConstInstances { def of[B]: OfPartiallyApplied[B] = new OfPartiallyApplied } -sealed abstract private[data] class ConstInstances extends ConstInstancesBinCompat0 { +sealed abstract private[data] class ConstInstances extends ConstInstances0 { implicit def catsDataUpperBoundedForConst[A, B](implicit A: UpperBounded[A]): UpperBounded[Const[A, B]] = new UpperBounded[Const[A, B]] { override def partialOrder: PartialOrder[Const[A, B]] = catsDataPartialOrderForConst(A.partialOrder) @@ -206,22 +206,6 @@ sealed abstract private[data] class ConstInstances4 { new ConstContravariant[C] {} } -trait ConstInstancesBinCompat0 extends ConstInstances0 { - implicit def catsDataDecidableForConst[D: Monoid]: Decidable[Const[D, ?]] = - new Decidable[Const[D, ?]] { - override def unit: Const[D, Unit] = Const.empty[D, Unit] - override def contramap[A, B](fa: Const[D, A])(f: B => A): Const[D, B] = - fa.retag[B] - override def product[A, B](fa: Const[D, A], fb: Const[D, B]): Const[D, (A, B)] = - fa.retag[(A, B)].combine(fb.retag[(A, B)]) - def sum[A, B](fa: Const[D, A], fb: Const[D, B]): Const[D, Either[A, B]] = - fa.retag[Either[A, B]].combine(fb.retag[Either[A, B]]) - - // FIXME: This instance maybe should not exist unless we get Ring constraints - override def zero[A]: Const[D, INothing] = Const.empty[D, INothing] - } -} - sealed private[data] trait ConstFunctor[C] extends Functor[Const[C, *]] { def map[A, B](fa: Const[C, A])(f: A => B): Const[C, B] = fa.retag[B] diff --git a/docs/src/main/tut/typeclasses/decidable.md b/docs/src/main/tut/typeclasses/decidable.md index e7ae73f704..fe87ec1f90 100644 --- a/docs/src/main/tut/typeclasses/decidable.md +++ b/docs/src/main/tut/typeclasses/decidable.md @@ -14,12 +14,19 @@ It is the contravariant analogue of the [`Alternative`](alternative.html) type c ```tut:silent import cats.ContravariantMonoidal +import cats.data.INothing trait Decidable[F[_]] extends ContravariantMonoidal[F] { - def sum[A, B](fa: F[A], fb: F[B]): Either[F[A], F[B]] + def sum[A, B](fa: F[A], fb: F[B]): F[Either[A, B]] def decide[A, B, C](fa: F[A], fb: F[B])(f: C => Either[A, B]): F[C] = contramap(sum(fa, fb))(f) + + def zero[A]: F[INothing] +} +object Decidable { + def apply[F[_]](implicit dec: Decidable[F]): Decidable[F] = + dec } ``` @@ -32,30 +39,30 @@ The classic example of a `Decidable` is that of predicates `A => Boolean`, leani We can write the instance as: ```tut:silent -implicit val decideableForPredicates = new Decidable[? => Boolean] { - def empty[A]: A => Boolean = Function.const(false) - def unit: Unit => Boolean = Function.const(true) +implicit val decideableForPredicates = new Decidable[* => Boolean] { + def zero[A]: INothing => Boolean = _ => true + def unit: Unit => Boolean = Function.const(false) def contramap[A, B](fa: A => Boolean)(f: B => A): B => Boolean = fa.compose(f) def product[A, B](fa: A => Boolean, fb: B => Boolean): ((A, B)) => Boolean = (ab: (A, B)) => ab match { - case (a, b) => fa(a) && fb(b) + case (a, b) => fa(a) || fb(b) } def sum[A, B](fa: A => Boolean, fb: B => Boolean): Either[A, B] => Boolean = either => either.fold(fa, fb) } ``` -This can be used to combine predicates over both coproducts and products. +This can be used to combine predicates over both sum types and product types. ```tut def isEven(i: Int): Boolean = i % 2 == 0 def isDivisibleByThree(l: Long): Boolean = l % 3 == 0 def isEvenRightOrDivisibleThreeLeft: Either[Int, Long] => Boolean = - Decidable[? => Boolean].sum(isEven, isDivisibleByThree) + Decidable[* => Boolean].sum(isEven, isDivisibleByThree) -def isEvenRightAndDivisibleThreeLeft: (Int, Long) => Boolean = - Decidable[? => Boolean].product(isEven, isDivisibleByThree) +def isEvenRightAndDivisibleThreeLeft: ((Int, Long)) => Boolean = + Decidable[* => Boolean].product(isEven, isDivisibleByThree) ``` diff --git a/tests/src/test/scala/cats/tests/ConstSuite.scala b/tests/src/test/scala/cats/tests/ConstSuite.scala index 0636aa7c3f..1d4a1b1870 100644 --- a/tests/src/test/scala/cats/tests/ConstSuite.scala +++ b/tests/src/test/scala/cats/tests/ConstSuite.scala @@ -82,9 +82,6 @@ class ConstSuite extends CatsSuite { SerializableTests.serializable(ContravariantMonoidal[Const[String, *]]) ) - checkAll("Const[String, Int", DecidableTests[Const[String, *]].decidable[Int, Int, Int]) - checkAll("Decidable[Const[String, ?]]", SerializableTests.serializable(Decidable[Const[String, *]])) - checkAll("Const[*, *]", BifoldableTests[Const].bifoldable[Int, Int, Int]) checkAll("Bifoldable[Const]", SerializableTests.serializable(Bifoldable[Const])) From d94ad941275998f64ffdb8d952751b398e7a97b2 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 21 Jul 2020 18:31:11 -0700 Subject: [PATCH 29/87] Some clean up, breaks tests --- core/src/main/scala/cats/Invariant.scala | 4 +- core/src/main/scala/cats/Semigroupal.scala | 6 ++- core/src/main/scala/cats/data/IdT.scala | 2 +- core/src/main/scala/cats/data/Nested.scala | 24 ++++----- core/src/main/scala/cats/data/Tuple2K.scala | 34 ++++++------- .../main/scala/cats/laws/DecidableLaws.scala | 11 ++++- .../cats/laws/discipline/DecidableTests.scala | 49 ++----------------- .../test/scala/cats/tests/FunctionSuite.scala | 1 - .../src/test/scala/cats/tests/IdTSuite.scala | 7 +-- .../test/scala/cats/tests/KleisliSuite.scala | 12 ++--- .../test/scala/cats/tests/NestedSuite.scala | 18 ++++--- tests/src/test/scala/cats/tests/OpSuite.scala | 1 - .../test/scala/cats/tests/OptionTSuite.scala | 8 +-- .../test/scala/cats/tests/Tuple2KSuite.scala | 9 ++-- 14 files changed, 76 insertions(+), 110 deletions(-) diff --git a/core/src/main/scala/cats/Invariant.scala b/core/src/main/scala/cats/Invariant.scala index 2d62f904a5..ad18bbd738 100644 --- a/core/src/main/scala/cats/Invariant.scala +++ b/core/src/main/scala/cats/Invariant.scala @@ -123,8 +123,6 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn cats.instances.sortedMap.catsStdInstancesForSortedMap[K] implicit def catsBimonadForFunction0: Bimonad[Function0] = cats.instances.function.catsStdBimonadForFunction0 implicit def catsMonadForFunction1[I]: Monad[I => *] = cats.instances.function.catsStdMonadForFunction1[I] - implicit def catsContravariantMonoidalForFunction1[R: Monoid]: ContravariantMonoidal[* => R] = - cats.instances.function.catsStdContravariantMonoidalForFunction1[R] implicit def catsFunctorForPair: Functor[λ[P => (P, P)]] = cats.instances.tuple.catsDataFunctorForPair implicit def catsInstancesForTry: MonadError[Try, Throwable] with CoflatMap[Try] = @@ -151,6 +149,8 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn cats.instances.order.catsDecidableForOrder implicit def catsDecidableForOrdering: Decidable[Ordering] = cats.instances.ordering.catsDecidableForOrdering + implicit def catsDecidableForPredicate: Decidable[* => Boolean] = + cats.instances.function.catsStdDecidableForPredicate implicit val catsInvariantMonoid: Invariant[Monoid] = new Invariant[Monoid] { diff --git a/core/src/main/scala/cats/Semigroupal.scala b/core/src/main/scala/cats/Semigroupal.scala index 3215ced9fb..cb140ccd0f 100644 --- a/core/src/main/scala/cats/Semigroupal.scala +++ b/core/src/main/scala/cats/Semigroupal.scala @@ -62,8 +62,8 @@ object Semigroupal extends ScalaVersionSpecificSemigroupalInstances with Semigro cats.instances.sortedMap.catsStdInstancesForSortedMap[K] implicit def catsSemigroupalForFunction1[A]: Semigroupal[A => *] = cats.instances.function.catsStdMonadForFunction1[A] - implicit def catsSemigroupalForFunction1Contravariant[R: Monoid]: Semigroupal[* => R] = - cats.instances.function.catsStdContravariantMonoidalForFunction1[R] +// implicit def catsSemigroupalForFunction1Contravariant[R: Monoid]: Semigroupal[* => R] = +// cats.instances.function.catsStdContravariantMonoidalForFunction1[R] implicit def catsSemigroupalForFunction0: Semigroupal[Function0] = cats.instances.function.catsStdBimonadForFunction0 @@ -83,6 +83,8 @@ object Semigroupal extends ScalaVersionSpecificSemigroupalInstances with Semigro cats.instances.invariant.catsInvariantMonoidalSemigroup implicit val catsSemigroupalForCommutativeSemigroup: Semigroupal[CommutativeSemigroup] = cats.instances.invariant.catsInvariantMonoidalCommutativeSemigroup + implicit val catsSemigroupalForPredicate: Semigroupal[* => Boolean] = + cats.instances.function.catsStdDecidableForPredicate /* ======================================================================== */ /* THE FOLLOWING CODE IS MANAGED BY SIMULACRUM; PLEASE DO NOT EDIT!!!! */ diff --git a/core/src/main/scala/cats/data/IdT.scala b/core/src/main/scala/cats/data/IdT.scala index 9cc6a15403..cdc0478663 100644 --- a/core/src/main/scala/cats/data/IdT.scala +++ b/core/src/main/scala/cats/data/IdT.scala @@ -172,7 +172,7 @@ sealed abstract private[data] class IdTInstances5 extends IdTInstances6 { implicit def catsDataDecidableForIdT[F[_]](implicit F: Decidable[F] - ): Decidable[IdT[F, ?]] = + ): Decidable[IdT[F, *]] = new IdTDecidable[F] { implicit val F0: Decidable[F] = F } } diff --git a/core/src/main/scala/cats/data/Nested.scala b/core/src/main/scala/cats/data/Nested.scala index b324a4e33d..35f4c07154 100644 --- a/core/src/main/scala/cats/data/Nested.scala +++ b/core/src/main/scala/cats/data/Nested.scala @@ -44,12 +44,6 @@ sealed abstract private[data] class NestedInstances extends NestedInstances0 { val FG: NonEmptyTraverse[λ[α => F[G[α]]]] = NonEmptyTraverse[F].compose[G] } - implicit def catsDataDecidableForApplicativeForNested[F[_]: Applicative, G[_]: Decidable] - : Decidable[Nested[F, G, *]] = - new NestedDecidable[F, G] with NestedContravariant[F, G] { - val FG: Decidable[λ[α => F[G[α]]]] = Applicative[F].composeDecidable[G] - } - implicit def catsDataDeferForNested[F[_], G[_]](implicit F: Defer[F]): Defer[Nested[F, G, *]] = new Defer[Nested[F, G, *]] { def defer[A](fa: => Nested[F, G, A]): Nested[F, G, A] = @@ -80,12 +74,6 @@ sealed abstract private[data] class NestedInstances0 extends NestedInstances1 { implicit val F: Functor[F] = F0 implicit val G: FunctorFilter[G] = G0 } - - implicit def catsDataContravariantMonoidalForApplicativeForNested[F[_]: Applicative, G[_]: ContravariantMonoidal] - : ContravariantMonoidal[Nested[F, G, *]] = - new NestedContravariantMonoidal[F, G] with NestedContravariant[F, G] { - val FG: ContravariantMonoidal[λ[α => F[G[α]]]] = Applicative[F].composeContravariantMonoidal[G] - } } sealed abstract private[data] class NestedInstances1 extends NestedInstances2 { @@ -94,6 +82,12 @@ sealed abstract private[data] class NestedInstances1 extends NestedInstances2 { val FG: Reducible[λ[α => F[G[α]]]] = Reducible[F].compose[G] } + implicit def catsDataDecidableForApplicativeForNested[F[_]: Applicative, G[_]: Decidable] + : Decidable[Nested[F, G, *]] = + new NestedDecidable[F, G] with NestedContravariant[F, G] { + val FG: Decidable[λ[α => F[G[α]]]] = Applicative[F].composeDecidable[G] + } + implicit def catsDataFunctorForContravariantForNested[F[_]: Contravariant, G[_]: Contravariant] : Functor[Nested[F, G, *]] = new NestedFunctor[F, G] { @@ -107,6 +101,12 @@ sealed abstract private[data] class NestedInstances2 extends NestedInstances3 { val FG: Foldable[λ[α => F[G[α]]]] = Foldable[F].compose[G] } + implicit def catsDataContravariantMonoidalForApplicativeForNested[F[_]: Applicative, G[_]: ContravariantMonoidal] + : ContravariantMonoidal[Nested[F, G, *]] = + new NestedContravariantMonoidal[F, G] with NestedContravariant[F, G] { + val FG: ContravariantMonoidal[λ[α => F[G[α]]]] = Applicative[F].composeContravariantMonoidal[G] + } + implicit def catsDataContravariantForCovariantNested[F[_]: Contravariant, G[_]: Functor] : Contravariant[Nested[F, G, *]] = new NestedContravariant[F, G] { diff --git a/core/src/main/scala/cats/data/Tuple2K.scala b/core/src/main/scala/cats/data/Tuple2K.scala index 205867fd27..e3bef4df6f 100644 --- a/core/src/main/scala/cats/data/Tuple2K.scala +++ b/core/src/main/scala/cats/data/Tuple2K.scala @@ -64,14 +64,6 @@ sealed abstract private[data] class Tuple2KInstances0 extends Tuple2KInstances1 def F: Traverse[F] = FF def G: Traverse[G] = GF } - implicit def catsDataContravariantMonoidalForTuple2k[F[_], G[_]](implicit - FD: ContravariantMonoidal[F], - GD: ContravariantMonoidal[G] - ): ContravariantMonoidal[λ[α => Tuple2K[F, G, α]]] = - new Tuple2KContravariantMonoidal[F, G] with Tuple2KContravariant[F, G] { - def F: ContravariantMonoidal[F] = FD - def G: ContravariantMonoidal[G] = GD - } implicit def catsDataEqForTuple2K[F[_], G[_], A](implicit FF: Eq[F[A]], GG: Eq[G[A]]): Eq[Tuple2K[F, G, A]] = new Eq[Tuple2K[F, G, A]] { def eqv(x: Tuple2K[F, G, A], y: Tuple2K[F, G, A]): Boolean = @@ -88,6 +80,14 @@ sealed abstract private[data] class Tuple2KInstances1 extends Tuple2KInstances2 def F: Alternative[F] = FF def G: Alternative[G] = GG } + implicit def catsDataContravariantMonoidalForTuple2k[F[_], G[_]](implicit + FD: ContravariantMonoidal[F], + GD: ContravariantMonoidal[G] + ): ContravariantMonoidal[λ[α => Tuple2K[F, G, α]]] = + new Tuple2KContravariantMonoidal[F, G] with Tuple2KContravariant[F, G] { + def F: ContravariantMonoidal[F] = FD + def G: ContravariantMonoidal[G] = GD + } implicit def catsDataFoldableForTuple2K[F[_], G[_]](implicit FF: Foldable[F], GF: Foldable[G] @@ -96,16 +96,6 @@ sealed abstract private[data] class Tuple2KInstances1 extends Tuple2KInstances2 def F: Foldable[F] = FF def G: Foldable[G] = GF } - - implicit def catsDataContravariantForTuple2K[F[_], G[_]](implicit - FC: Contravariant[F], - GC: Contravariant[G] - ): Contravariant[λ[α => Tuple2K[F, G, α]]] = - new Tuple2KContravariant[F, G] { - def F: Contravariant[F] = FC - def G: Contravariant[G] = GC - } - } sealed abstract private[data] class Tuple2KInstances2 extends Tuple2KInstances3 { @@ -117,6 +107,14 @@ sealed abstract private[data] class Tuple2KInstances2 extends Tuple2KInstances3 def F: Monad[F] = FM def G: Monad[G] = GM } + implicit def catsDataContravariantForTuple2K[F[_], G[_]](implicit + FC: Contravariant[F], + GC: Contravariant[G] + ): Contravariant[λ[α => Tuple2K[F, G, α]]] = + new Tuple2KContravariant[F, G] { + def F: Contravariant[F] = FC + def G: Contravariant[G] = GC + } implicit def catsDataMonoidKForTuple2K[F[_], G[_]](implicit FF: MonoidK[F], GG: MonoidK[G] diff --git a/laws/src/main/scala/cats/laws/DecidableLaws.scala b/laws/src/main/scala/cats/laws/DecidableLaws.scala index a119f4179e..ab5085a30a 100644 --- a/laws/src/main/scala/cats/laws/DecidableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecidableLaws.scala @@ -11,8 +11,15 @@ trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { fa: F[A], fb: F[B], fc: F[C] - ): (F[Either[A, Either[B, C]]], F[Either[Either[A, B], C]]) = - (F.sum(fa, F.sum(fb, fc)), F.sum(F.sum(fa, fb), fc)) + ): IsEq[F[Either[Either[A, B], C]]] = + F.contramap[Either[A, Either[B, C]], Either[Either[A, B], C]]( + F.sum(fa, F.sum(fb, fc)))( + { + case Left(Left(x)) => Left(x) + case Left(Right(x)) => Right(Left(x)) + case Right(x) => Right(Right(x)) + } + ) <-> F.sum(F.sum(fa, fb), fc) def decideableRightDistributivity[A, B, C](fa: F[A], fb: F[B], f: C => A, g: C => B): IsEq[F[Either[C, C]]] = F.contramap(F.sum(fa, fb))((eit: Either[C, C]) => diff --git a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala index 9e628634a6..585b941413 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala @@ -21,8 +21,7 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { EqFABC: Eq[F[(A, B, C)]], EqCC: Eq[F[Either[C, C]]], EqFEitABC: Eq[F[Either[Either[A, B], C]]], - iso: SemigroupalTests.Isomorphisms[F], - iso2: DecidableTests.Isomorphisms[F] + iso: SemigroupalTests.Isomorphisms[F] ): RuleSet = new RuleSet { val name = "decideable" @@ -31,9 +30,8 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { val props = Seq( "decideable right absorption" -> forAll(laws.decideableDecideRightAbsorption[A] _), - "decideable sum associativity" -> forAll((fa: F[A], fb: F[B], fc: F[C]) => - iso2.associativity(laws.decideableSumAssociativity[A, B, C](fa, fb, fc)) - ), + "decideable sum associativity" -> + forAll(laws.decideableSumAssociativity[A, B, C] _), "decideable right distributivity" -> forAll(laws.decideableRightDistributivity[A, B, C] _) ) @@ -41,45 +39,6 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { } object DecidableTests { - def apply[F[_]: Decidable](implicit ev: Isomorphisms[F]): DecidableTests[F] = + def apply[F[_]: Decidable]: DecidableTests[F] = new DecidableTests[F] { def laws: DecidableLaws[F] = DecidableLaws[F] } - - trait Isomorphisms[F[_]] { - def associativity[A, B, C]( - fs: (F[Either[A, Either[B, C]]], F[Either[Either[A, B], C]]) - ): IsEq[F[Either[Either[A, B], C]]] - def leftIdentity[A](fs: (F[Either[Nothing, A]], F[A])): IsEq[F[A]] - def rightIdentity[A](fs: (F[Either[A, Nothing]], F[A])): IsEq[F[A]] - } - - object Isomorphisms { - private def absurd[A](n: Nothing): A = n.asInstanceOf[A] - - import cats.kernel.laws._ - implicit def invariant[F[_]](implicit F: Invariant[F]): Isomorphisms[F] = - new Isomorphisms[F] { - def associativity[A, B, C]( - fs: (F[Either[A, Either[B, C]]], F[Either[Either[A, B], C]]) - ): IsEq[F[Either[Either[A, B], C]]] = - F.imap(fs._1) { - case Left(a) => Left(Left(a)) - case Right(Left(b)) => Left(Right(b)) - case Right(Right(c)) => Right(c) - } { - case Left(Left(a)) => Left(a) - case Left(Right(b)) => Right(Left(b)) - case Right(c) => Right(Right(c)) - } <-> fs._2 - - def leftIdentity[A](fs: (F[Either[Nothing, A]], F[A])): IsEq[F[A]] = - F.imap(fs._1) { case Right(a) => a; case Left(n) => absurd[A](n) } { (a: A) => - Right(a) - } <-> fs._2 - - def rightIdentity[A](fs: (F[Either[A, Nothing]], F[A])): IsEq[F[A]] = - F.imap(fs._1) { case Left(a) => a; case Right(n) => absurd[A](n) } { (a: A) => - Left(a) - } <-> fs._2 - } - } } diff --git a/tests/src/test/scala/cats/tests/FunctionSuite.scala b/tests/src/test/scala/cats/tests/FunctionSuite.scala index f0b7511f0d..a2a6629019 100644 --- a/tests/src/test/scala/cats/tests/FunctionSuite.scala +++ b/tests/src/test/scala/cats/tests/FunctionSuite.scala @@ -163,7 +163,6 @@ class FunctionSuite extends CatsSuite { // Isos for Decidable implicit val isoCodomainBoolean = SemigroupalTests.Isomorphisms.invariant[Function1[*, Boolean]] - implicit val isoCoproductCodomain = DecidableTests.Isomorphisms.invariant[Function1[*, Boolean]] checkAll("Function1[?, Boolean]", DecidableTests[Function1[*, Boolean]].decidable[MiniInt, MiniInt, MiniInt]) checkAll("Decidable[? => Boolean]", SerializableTests.serializable(Decidable[Function1[*, Boolean]])) diff --git a/tests/src/test/scala/cats/tests/IdTSuite.scala b/tests/src/test/scala/cats/tests/IdTSuite.scala index 7b5ac55304..a6d12bfac5 100644 --- a/tests/src/test/scala/cats/tests/IdTSuite.scala +++ b/tests/src/test/scala/cats/tests/IdTSuite.scala @@ -66,9 +66,10 @@ class IdTSuite extends CatsSuite { } { - implicit val coproductIso = DecidableTests.Isomorphisms.invariant[IdT[Const[String, ?], ?]] - checkAll("IdT[Const[String, ?], ?]", DecidableTests[IdT[Const[String, ?], ?]].decidable[Int, Int, Int]) - checkAll("Decidable[IdT[Const[String, ?], ?]]", SerializableTests.serializable(Decidable[IdT[Const[String, ?], ?]])) + implicit val F: Decidable[IdT[* => Boolean, *]] = cats.data.IdT.catsDataDecidableForIdT[* => Boolean] + + checkAll("IdT[* => Boolean], ?]", DecidableTests[IdT[* => Boolean, *]].decidable[MiniInt, MiniInt, MiniInt]) + checkAll("Decidable[IdT[* => Boolean, ?], ?]]", SerializableTests.serializable(Decidable[IdT[* => Boolean, *]])) } { diff --git a/tests/src/test/scala/cats/tests/KleisliSuite.scala b/tests/src/test/scala/cats/tests/KleisliSuite.scala index dbd88283cf..396941d312 100644 --- a/tests/src/test/scala/cats/tests/KleisliSuite.scala +++ b/tests/src/test/scala/cats/tests/KleisliSuite.scala @@ -106,21 +106,21 @@ class KleisliSuite extends CatsSuite { { implicit val catsDataDecidableForKleisli = - Kleisli.catsDataDecidableForKleisli[Const[String, ?], Int] - checkAll("Kleisli[Const[String, ?], Int, Int]", - DecidableTests[Kleisli[Const[String, ?], MiniInt, ?]].decidable[Int, Int, Int] + Kleisli.catsDataDecidableForKleisli[* => Boolean, Int] + checkAll("Kleisli[* => Boolean, Int, Int]", + DecidableTests[Kleisli[* => Boolean, MiniInt, *]].decidable[Int, Int, Int] ) checkAll( "Decidable[Kleisli[Option, Int, ?]]", - SerializableTests.serializable[Decidable[Kleisli[Const[String, ?], Int, ?]]](catsDataDecidableForKleisli) + SerializableTests.serializable[Decidable[Kleisli[* => Boolean, Int, ?]]](catsDataDecidableForKleisli) ) } { implicit val catsDataContravariantMonoidalForKleisli = - Kleisli.catsDataContravariantMonoidalForKleisli[Const[String, ?], Int] + Kleisli.catsDataContravariantMonoidalForKleisli[Const[String, *], Int] checkAll("Kleisli[Const[String, ?], MiniInt, ?]", - ContravariantMonoidalTests[Kleisli[Const[String, ?], MiniInt, ?]].contravariantMonoidal[Int, Int, Int] + ContravariantMonoidalTests[Kleisli[Const[String, *], MiniInt, *]].contravariantMonoidal[Int, Int, Int] ) checkAll("ContravariantMonoidal[Kleisli[Option, Int, ?]]", SerializableTests.serializable(ContravariantMonoidal[Kleisli[Const[String, ?], Int, ?]]) diff --git a/tests/src/test/scala/cats/tests/NestedSuite.scala b/tests/src/test/scala/cats/tests/NestedSuite.scala index de4f6cb45c..353fda7c4b 100644 --- a/tests/src/test/scala/cats/tests/NestedSuite.scala +++ b/tests/src/test/scala/cats/tests/NestedSuite.scala @@ -2,6 +2,7 @@ package cats.tests import cats._ import cats.data._ +import cats.laws.discipline.SemigroupalTests.Isomorphisms import cats.laws.discipline._ import cats.laws.discipline.SemigroupalTests.Isomorphisms._ import cats.laws.discipline.arbitrary._ @@ -104,22 +105,23 @@ class NestedSuite extends CatsSuite { { // Applicative + ContravariantMonoidal functor composition +// implicit val isos = Isomorphisms.invariant[Nested[Option, Const[String, *], *]] checkAll("Nested[Option, Const[String, *], *]", - ContravariantMonoidalTests[Nested[Option, Const[String, *], *]].contravariantMonoidal[Int, Int, Int] + ContravariantMonoidalTests[λ[α => Nested[Option, Const[String, *], α]]].contravariantMonoidal[Int, Int, Int] ) checkAll("ContravariantMonoidal[Nested[Option, Const[String, *], *]", - SerializableTests.serializable(ContravariantMonoidal[Nested[Option, Const[String, *], *]]) + SerializableTests.serializable(ContravariantMonoidal[λ[α => Nested[Option, Const[String, *], α]]]) ) } { - // Applicative + Decidable functor compositoin - implicit val coproductIsos = DecidableTests.Isomorphisms.invariant[Nested[Option, Const[String, ?], ?]] - checkAll("Nested[Option, Const[String, ?], ?]", - DecidableTests[Nested[Option, Const[String, ?], ?]].decidable[Int, Int, Int] + // Applicative + Decidable functor composition + implicit val isos = Isomorphisms.invariant[Nested[Option, Const[String, *], *]] + checkAll("Nested[Option, * => Boolean, ?]", + DecidableTests[Nested[Option, * => Boolean, *]].decidable[Int, Int, Int] ) - checkAll("Decidable[Nested[Option, Const[String, ?], ?]]", - SerializableTests.serializable(Decidable[Nested[Option, Const[String, ?], ?]]) + checkAll("Decidable[Nested[Option, * => Boolean, ?]]", + SerializableTests.serializable(Decidable[Nested[Option, * => Boolean, *]]) ) } diff --git a/tests/src/test/scala/cats/tests/OpSuite.scala b/tests/src/test/scala/cats/tests/OpSuite.scala index 858c2c847b..eeed5816a3 100644 --- a/tests/src/test/scala/cats/tests/OpSuite.scala +++ b/tests/src/test/scala/cats/tests/OpSuite.scala @@ -24,7 +24,6 @@ class OpSuite extends CatsSuite { { implicit val catsDataDecidableForOp = Op.catsDataDecidableForOp[Function1, Int] - implicit val coproductIsos = DecidableTests.Isomorphisms.invariant[Op[Function1, Int, *]] checkAll("Op[Function1, Monoid, ?]", DecidableTests[Op[Function1, Int, *]].decidable[MiniInt, MiniInt, MiniInt]) checkAll("Decidable[Op[Function1, Monoid, ?]]", SerializableTests.serializable(Decidable[Op[Function1, Int, *]])) } diff --git a/tests/src/test/scala/cats/tests/OptionTSuite.scala b/tests/src/test/scala/cats/tests/OptionTSuite.scala index 0b7985e5b8..9f89fbce64 100644 --- a/tests/src/test/scala/cats/tests/OptionTSuite.scala +++ b/tests/src/test/scala/cats/tests/OptionTSuite.scala @@ -99,11 +99,11 @@ class OptionTSuite extends CatsSuite { { // F has a Decidable - implicit val iso = SemigroupalTests.Isomorphisms.invariant[OptionT[Const[String, *], *]] + implicit val iso = SemigroupalTests.Isomorphisms.invariant[OptionT[* => Boolean, *]] - checkAll("OptionT[Const[String, ?], Int]", DecidableTests[OptionT[Const[String, *], *]].decidable[Int, Int, Int]) - checkAll("Decidable[OptionT[Const[String, ?], Int]]", - SerializableTests.serializable(Decidable[OptionT[Const[String, *], *]]) + checkAll("OptionT[* => Boolean, Int]", DecidableTests[OptionT[* => Boolean, *]].decidable[Int, Int, Int]) + checkAll("Decidable[OptionT[* => Boolean, Int]]", + SerializableTests.serializable(Decidable[OptionT[* => Boolean, *]]) ) // F has a ContravariantMonoidal diff --git a/tests/src/test/scala/cats/tests/Tuple2KSuite.scala b/tests/src/test/scala/cats/tests/Tuple2KSuite.scala index 57298ea0d3..2a0e2f06a7 100644 --- a/tests/src/test/scala/cats/tests/Tuple2KSuite.scala +++ b/tests/src/test/scala/cats/tests/Tuple2KSuite.scala @@ -28,6 +28,8 @@ class Tuple2KSuite extends CatsSuite { SerializableTests.serializable(Contravariant[λ[α => Tuple2K[Show, Order, α]]]) ) + implicit val isoConst: Isomorphisms[λ[α => Tuple2K[Const[String, *], Const[String, *], α]]] = + Isomorphisms.invariant[λ[α => Tuple2K[Const[String, *], Const[String, *], α]]] checkAll( "Tuple2K[Const[String, *], Const[Int, *], Int]", ContravariantMonoidalTests[λ[α => Tuple2K[Const[String, *], Const[Int, *], α]]].contravariantMonoidal[Int, Int, Int] @@ -37,15 +39,12 @@ class Tuple2KSuite extends CatsSuite { SerializableTests.serializable(ContravariantMonoidal[λ[α => Tuple2K[Const[String, *], Const[Int, *], α]]]) ) - // Coproduct isos for DecidableTests - implicit val coproductIso = DecidableTests.Isomorphisms.invariant[Tuple2K[Const[String, ?], Const[Int, ?], ?]] - checkAll("Tuple2K[Const[String, ?], Const[Int, ?], Long]", - DecidableTests[λ[α => Tuple2K[Const[String, ?], Const[Int, ?], α]]].decidable[Long, Long, Long] + DecidableTests[λ[α => Tuple2K[* => Boolean, * => Boolean, α]]].decidable[Long, Long, Long] ) checkAll( "Decidable[Tuple2K[Const[String, ?], Const[Int, ?], Long]]", - SerializableTests.serializable(Decidable[λ[α => Tuple2K[Const[String, ?], Const[Int, ?], α]]]) + SerializableTests.serializable(Decidable[λ[α => Tuple2K[* => Boolean, * => Boolean, α]]]) ) checkAll("Show[Tuple2K[Option, Option, Int]]", SerializableTests.serializable(Show[Tuple2K[Option, Option, Int]])) From 7e357aa640ca9a00fdc3f585e61c33ddd57e138d Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 21 Jul 2020 19:09:00 -0700 Subject: [PATCH 30/87] Missed a bit --- .../main/scala/cats/laws/DecidableLaws.scala | 16 +++++++++++++--- .../cats/laws/discipline/DecidableTests.scala | 17 +++++++++++------ tests/src/test/scala/cats/tests/IdTSuite.scala | 2 +- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/laws/src/main/scala/cats/laws/DecidableLaws.scala b/laws/src/main/scala/cats/laws/DecidableLaws.scala index ab5085a30a..d05bfaf961 100644 --- a/laws/src/main/scala/cats/laws/DecidableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecidableLaws.scala @@ -4,10 +4,13 @@ package laws trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { implicit override def F: Decidable[F] - def decideableDecideRightAbsorption[A](fa: F[A]): IsEq[F[A]] = + def decidableDecideLeftIdentity[A](fa: F[A]): IsEq[F[A]] = + F.decide(fa, F.trivial[A])(Left.apply[A, A]) <-> fa + + def decidableDecideRightIdentity[A](fa: F[A]): IsEq[F[A]] = F.decide(F.trivial[A], fa)(Right.apply[A, A]) <-> fa - def decideableSumAssociativity[A, B, C]( + def decidableSumAssociativity[A, B, C]( fa: F[A], fb: F[B], fc: F[C] @@ -21,13 +24,20 @@ trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { } ) <-> F.sum(F.sum(fa, fb), fc) - def decideableRightDistributivity[A, B, C](fa: F[A], fb: F[B], f: C => A, g: C => B): IsEq[F[Either[C, C]]] = + def decidableRightDistributivity[A, B, C](fa: F[A], fb: F[B], f: C => A, g: C => B): IsEq[F[Either[C, C]]] = F.contramap(F.sum(fa, fb))((eit: Either[C, C]) => eit.fold( f.andThen(Left.apply), g.andThen(Right.apply) ) ) <-> F.sum(F.contramap(fa)(f), F.contramap(fb)(g)) + + def decidableRightDistributivitySum[A, B, C](fa: F[A], fb: F[B], fc: F[C]): IsEq[F[(A, Either[B, C])]] = + F.product(fa, F.sum(fb, fc)) <-> + F.contramap(F.sum(F.product(fa, fb), F.product(fa, fc)))({ + case (a, Left(b)) => Left((a, b)) + case (a, Right(c)) => Right((a, c)) + }) } object DecidableLaws { diff --git a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala index 585b941413..074647d32f 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala @@ -21,6 +21,7 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { EqFABC: Eq[F[(A, B, C)]], EqCC: Eq[F[Either[C, C]]], EqFEitABC: Eq[F[Either[Either[A, B], C]]], + EqFTupAEitBC: Eq[F[(A, Either[B, C])]], iso: SemigroupalTests.Isomorphisms[F] ): RuleSet = new RuleSet { @@ -28,12 +29,16 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { val parents = Seq(contravariantMonoidal[A, B, C]) val bases = Seq.empty val props = Seq( - "decideable right absorption" -> - forAll(laws.decideableDecideRightAbsorption[A] _), - "decideable sum associativity" -> - forAll(laws.decideableSumAssociativity[A, B, C] _), - "decideable right distributivity" -> - forAll(laws.decideableRightDistributivity[A, B, C] _) + "decideable left identity" -> + forAll(laws.decidableDecideLeftIdentity[A] _), + "decidable right identity" -> + forAll(laws.decidableDecideRightIdentity[A] _), + "decidable sum associativity" -> + forAll(laws.decidableSumAssociativity[A, B, C] _), + "decidable right distributivity" -> + forAll(laws.decidableRightDistributivity[A, B, C] _), + "dedicable right sum distributivituy" -> + forAll(laws.decidableRightDistributivitySum[A, B, C] _) ) } } diff --git a/tests/src/test/scala/cats/tests/IdTSuite.scala b/tests/src/test/scala/cats/tests/IdTSuite.scala index a6d12bfac5..2c646e3522 100644 --- a/tests/src/test/scala/cats/tests/IdTSuite.scala +++ b/tests/src/test/scala/cats/tests/IdTSuite.scala @@ -67,7 +67,7 @@ class IdTSuite extends CatsSuite { { implicit val F: Decidable[IdT[* => Boolean, *]] = cats.data.IdT.catsDataDecidableForIdT[* => Boolean] - + checkAll("IdT[* => Boolean], ?]", DecidableTests[IdT[* => Boolean, *]].decidable[MiniInt, MiniInt, MiniInt]) checkAll("Decidable[IdT[* => Boolean, ?], ?]]", SerializableTests.serializable(Decidable[IdT[* => Boolean, *]])) } From 12ef1f905f87d13ee1d22b73e01fc9057c4c4227 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 21 Jul 2020 20:34:51 -0700 Subject: [PATCH 31/87] Significantly improved tests --- .../scala/cats/tests/ContravariantSuite.scala | 30 ++++--------------- .../src/test/scala/cats/tests/IdTSuite.scala | 6 ++-- .../test/scala/cats/tests/KleisliSuite.scala | 8 ++--- .../test/scala/cats/tests/NestedSuite.scala | 10 +++---- .../test/scala/cats/tests/OptionTSuite.scala | 10 ++++--- .../src/test/scala/cats/tests/Predicate.scala | 29 ++++++++++++++++++ .../test/scala/cats/tests/Tuple2KSuite.scala | 8 ++--- 7 files changed, 54 insertions(+), 47 deletions(-) create mode 100644 tests/src/test/scala/cats/tests/Predicate.scala diff --git a/tests/src/test/scala/cats/tests/ContravariantSuite.scala b/tests/src/test/scala/cats/tests/ContravariantSuite.scala index cfba03766e..ca8849e207 100644 --- a/tests/src/test/scala/cats/tests/ContravariantSuite.scala +++ b/tests/src/test/scala/cats/tests/ContravariantSuite.scala @@ -1,13 +1,11 @@ package cats.tests -import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal} import cats.data.Const -import cats.kernel.{Eq, Monoid, Semigroup} import cats.kernel.laws.discipline.{MonoidTests, SemigroupTests} -import cats.laws.discipline.{ContravariantMonoidalTests, ExhaustiveCheck, MiniInt} +import cats.kernel.{Monoid, Semigroup} import cats.laws.discipline.arbitrary._ -import cats.laws.discipline.eq._ -import org.scalacheck.{Arbitrary, Cogen} +import cats.laws.discipline.{DecidableTests, MiniInt} +import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal} class ContravariantSuite extends CatsSuite { @@ -21,25 +19,9 @@ class ContravariantSuite extends CatsSuite { } } - case class Predicate[A](run: A => Boolean) - - implicit val contravariantMonoidalPredicate: ContravariantMonoidal[Predicate] = - new ContravariantMonoidal[Predicate] { - def unit: Predicate[Unit] = Predicate[Unit](Function.const(true)) - def product[A, B](fa: Predicate[A], fb: Predicate[B]): Predicate[(A, B)] = - Predicate(x => fa.run(x._1) && fb.run(x._2)) - def contramap[A, B](fa: Predicate[A])(f: B => A): Predicate[B] = - Predicate(x => fa.run(f(x))) - } - - implicit def eqPredicate[A: ExhaustiveCheck]: Eq[Predicate[A]] = - Eq.by[Predicate[A], A => Boolean](_.run) - - implicit def arbPredicate[A: Cogen]: Arbitrary[Predicate[A]] = - Arbitrary(implicitly[Arbitrary[A => Boolean]].arbitrary.map(f => Predicate(f))) - - checkAll("ContravariantMonoidal[Predicate]", - ContravariantMonoidalTests[Predicate].contravariantMonoidal[Boolean, Boolean, Boolean] + checkAll( + "Decidable[Predicate]", + DecidableTests[Predicate].decidable[Boolean, Boolean, Boolean] ) { diff --git a/tests/src/test/scala/cats/tests/IdTSuite.scala b/tests/src/test/scala/cats/tests/IdTSuite.scala index 2c646e3522..82e7c5146f 100644 --- a/tests/src/test/scala/cats/tests/IdTSuite.scala +++ b/tests/src/test/scala/cats/tests/IdTSuite.scala @@ -66,10 +66,8 @@ class IdTSuite extends CatsSuite { } { - implicit val F: Decidable[IdT[* => Boolean, *]] = cats.data.IdT.catsDataDecidableForIdT[* => Boolean] - - checkAll("IdT[* => Boolean], ?]", DecidableTests[IdT[* => Boolean, *]].decidable[MiniInt, MiniInt, MiniInt]) - checkAll("Decidable[IdT[* => Boolean, ?], ?]]", SerializableTests.serializable(Decidable[IdT[* => Boolean, *]])) + checkAll("IdT[* => Boolean], ?]", DecidableTests[IdT[Predicate, *]].decidable[MiniInt, MiniInt, MiniInt]) + checkAll("Decidable[IdT[* => Boolean, ?], ?]]", SerializableTests.serializable(Decidable[IdT[Predicate, *]])) } { diff --git a/tests/src/test/scala/cats/tests/KleisliSuite.scala b/tests/src/test/scala/cats/tests/KleisliSuite.scala index 396941d312..03e0f30b99 100644 --- a/tests/src/test/scala/cats/tests/KleisliSuite.scala +++ b/tests/src/test/scala/cats/tests/KleisliSuite.scala @@ -105,14 +105,12 @@ class KleisliSuite extends CatsSuite { checkAll("Alternative[Kleisli[Option, Int, *]]", SerializableTests.serializable(Alternative[Kleisli[Option, Int, *]])) { - implicit val catsDataDecidableForKleisli = - Kleisli.catsDataDecidableForKleisli[* => Boolean, Int] - checkAll("Kleisli[* => Boolean, Int, Int]", - DecidableTests[Kleisli[* => Boolean, MiniInt, *]].decidable[Int, Int, Int] + checkAll("Kleisli[Predicate, MiniInt, MiniInt]", + DecidableTests[Kleisli[Predicate, MiniInt, *]].decidable[MiniInt, MiniInt, MiniInt] ) checkAll( "Decidable[Kleisli[Option, Int, ?]]", - SerializableTests.serializable[Decidable[Kleisli[* => Boolean, Int, ?]]](catsDataDecidableForKleisli) + SerializableTests.serializable[Decidable[Kleisli[Predicate, MiniInt, *]]](Decidable[Kleisli[Predicate, MiniInt, *]]) ) } diff --git a/tests/src/test/scala/cats/tests/NestedSuite.scala b/tests/src/test/scala/cats/tests/NestedSuite.scala index 353fda7c4b..375d4cb31f 100644 --- a/tests/src/test/scala/cats/tests/NestedSuite.scala +++ b/tests/src/test/scala/cats/tests/NestedSuite.scala @@ -2,7 +2,6 @@ package cats.tests import cats._ import cats.data._ -import cats.laws.discipline.SemigroupalTests.Isomorphisms import cats.laws.discipline._ import cats.laws.discipline.SemigroupalTests.Isomorphisms._ import cats.laws.discipline.arbitrary._ @@ -116,12 +115,11 @@ class NestedSuite extends CatsSuite { { // Applicative + Decidable functor composition - implicit val isos = Isomorphisms.invariant[Nested[Option, Const[String, *], *]] - checkAll("Nested[Option, * => Boolean, ?]", - DecidableTests[Nested[Option, * => Boolean, *]].decidable[Int, Int, Int] + checkAll("Nested[Option, Predicate, ?]", + DecidableTests[Nested[Option, Predicate, *]].decidable[MiniInt, MiniInt, MiniInt] ) - checkAll("Decidable[Nested[Option, * => Boolean, ?]]", - SerializableTests.serializable(Decidable[Nested[Option, * => Boolean, *]]) + checkAll("Decidable[Nested[Option, Predicate, ?]]", + SerializableTests.serializable(Decidable[Nested[Option, Predicate, *]]) ) } diff --git a/tests/src/test/scala/cats/tests/OptionTSuite.scala b/tests/src/test/scala/cats/tests/OptionTSuite.scala index 9f89fbce64..a89315a566 100644 --- a/tests/src/test/scala/cats/tests/OptionTSuite.scala +++ b/tests/src/test/scala/cats/tests/OptionTSuite.scala @@ -99,11 +99,13 @@ class OptionTSuite extends CatsSuite { { // F has a Decidable - implicit val iso = SemigroupalTests.Isomorphisms.invariant[OptionT[* => Boolean, *]] + implicit val iso = SemigroupalTests.Isomorphisms.invariant[OptionT[Predicate, *]]( + OptionT.catsDataDecidableForOptionT(Predicate.decidablePredicate) + ) - checkAll("OptionT[* => Boolean, Int]", DecidableTests[OptionT[* => Boolean, *]].decidable[Int, Int, Int]) - checkAll("Decidable[OptionT[* => Boolean, Int]]", - SerializableTests.serializable(Decidable[OptionT[* => Boolean, *]]) + checkAll("OptionT[Predicate, MiniInt]", DecidableTests[OptionT[Predicate, *]].decidable[MiniInt, MiniInt, MiniInt]) + checkAll("Decidable[OptionT[Predicate, MiniInt]]", + SerializableTests.serializable(Decidable[OptionT[Predicate, *]]) ) // F has a ContravariantMonoidal diff --git a/tests/src/test/scala/cats/tests/Predicate.scala b/tests/src/test/scala/cats/tests/Predicate.scala new file mode 100644 index 0000000000..54ad66e21e --- /dev/null +++ b/tests/src/test/scala/cats/tests/Predicate.scala @@ -0,0 +1,29 @@ +package cats.tests + +import cats.Decidable +import cats.data.INothing +import cats.kernel.Eq +import cats.laws.discipline.eq._ +import cats.laws.discipline.ExhaustiveCheck +import org.scalacheck.{Arbitrary, Cogen} + +case class Predicate[A](run: A => Boolean) +object Predicate { + implicit val decidablePredicate: Decidable[Predicate] = + new Decidable[Predicate] { + def unit: Predicate[Unit] = Predicate[Unit](Function.const(false)) + def product[A, B](fa: Predicate[A], fb: Predicate[B]): Predicate[(A, B)] = + Predicate(x => fa.run(x._1) || fb.run(x._2)) + def contramap[A, B](fa: Predicate[A])(f: B => A): Predicate[B] = + Predicate(x => fa.run(f(x))) + def sum[A, B](fa: Predicate[A], fb: Predicate[B]): Predicate[Either[A, B]] = + Predicate(_.fold(fa.run, fb.run)) + def zero[A]: Predicate[INothing] = Predicate(_ => true) + } + + implicit def eqPredicate[A: ExhaustiveCheck]: Eq[Predicate[A]] = + Eq.by[Predicate[A], A => Boolean](_.run) + + implicit def arbPredicate[A: Cogen]: Arbitrary[Predicate[A]] = + Arbitrary(implicitly[Arbitrary[A => Boolean]].arbitrary.map(f => Predicate(f))) +} diff --git a/tests/src/test/scala/cats/tests/Tuple2KSuite.scala b/tests/src/test/scala/cats/tests/Tuple2KSuite.scala index 2a0e2f06a7..c4ba3ee053 100644 --- a/tests/src/test/scala/cats/tests/Tuple2KSuite.scala +++ b/tests/src/test/scala/cats/tests/Tuple2KSuite.scala @@ -39,12 +39,12 @@ class Tuple2KSuite extends CatsSuite { SerializableTests.serializable(ContravariantMonoidal[λ[α => Tuple2K[Const[String, *], Const[Int, *], α]]]) ) - checkAll("Tuple2K[Const[String, ?], Const[Int, ?], Long]", - DecidableTests[λ[α => Tuple2K[* => Boolean, * => Boolean, α]]].decidable[Long, Long, Long] + checkAll("Tuple2K[Predicate, Predicate, MiniInt]", + DecidableTests[Tuple2K[Predicate, Predicate, *]].decidable[MiniInt, MiniInt, MiniInt] ) checkAll( - "Decidable[Tuple2K[Const[String, ?], Const[Int, ?], Long]]", - SerializableTests.serializable(Decidable[λ[α => Tuple2K[* => Boolean, * => Boolean, α]]]) + "Decidable[Tuple2K[Predicate, Predicate, MiniInt]]", + SerializableTests.serializable(Decidable[Tuple2K[Predicate, Predicate, *]]) ) checkAll("Show[Tuple2K[Option, Option, Int]]", SerializableTests.serializable(Show[Tuple2K[Option, Option, Int]])) From af15b3c35298238c7ac9644c14d9d8c8f90a1d65 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 21 Jul 2020 20:44:21 -0700 Subject: [PATCH 32/87] Formatter --- core/src/main/scala/cats/data/Nested.scala | 4 ++-- laws/src/main/scala/cats/laws/DecidableLaws.scala | 9 ++++----- tests/src/test/scala/cats/tests/KleisliSuite.scala | 4 +++- tests/src/test/scala/cats/tests/NestedSuite.scala | 10 ++++++---- tests/src/test/scala/cats/tests/OptionTSuite.scala | 4 +--- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/core/src/main/scala/cats/data/Nested.scala b/core/src/main/scala/cats/data/Nested.scala index 35f4c07154..8c0133468a 100644 --- a/core/src/main/scala/cats/data/Nested.scala +++ b/core/src/main/scala/cats/data/Nested.scala @@ -83,7 +83,7 @@ sealed abstract private[data] class NestedInstances1 extends NestedInstances2 { } implicit def catsDataDecidableForApplicativeForNested[F[_]: Applicative, G[_]: Decidable] - : Decidable[Nested[F, G, *]] = + : Decidable[Nested[F, G, *]] = new NestedDecidable[F, G] with NestedContravariant[F, G] { val FG: Decidable[λ[α => F[G[α]]]] = Applicative[F].composeDecidable[G] } @@ -102,7 +102,7 @@ sealed abstract private[data] class NestedInstances2 extends NestedInstances3 { } implicit def catsDataContravariantMonoidalForApplicativeForNested[F[_]: Applicative, G[_]: ContravariantMonoidal] - : ContravariantMonoidal[Nested[F, G, *]] = + : ContravariantMonoidal[Nested[F, G, *]] = new NestedContravariantMonoidal[F, G] with NestedContravariant[F, G] { val FG: ContravariantMonoidal[λ[α => F[G[α]]]] = Applicative[F].composeContravariantMonoidal[G] } diff --git a/laws/src/main/scala/cats/laws/DecidableLaws.scala b/laws/src/main/scala/cats/laws/DecidableLaws.scala index d05bfaf961..fd47776209 100644 --- a/laws/src/main/scala/cats/laws/DecidableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecidableLaws.scala @@ -15,12 +15,11 @@ trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { fb: F[B], fc: F[C] ): IsEq[F[Either[Either[A, B], C]]] = - F.contramap[Either[A, Either[B, C]], Either[Either[A, B], C]]( - F.sum(fa, F.sum(fb, fc)))( + F.contramap[Either[A, Either[B, C]], Either[Either[A, B], C]](F.sum(fa, F.sum(fb, fc)))( { - case Left(Left(x)) => Left(x) + case Left(Left(x)) => Left(x) case Left(Right(x)) => Right(Left(x)) - case Right(x) => Right(Right(x)) + case Right(x) => Right(Right(x)) } ) <-> F.sum(F.sum(fa, fb), fc) @@ -35,7 +34,7 @@ trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { def decidableRightDistributivitySum[A, B, C](fa: F[A], fb: F[B], fc: F[C]): IsEq[F[(A, Either[B, C])]] = F.product(fa, F.sum(fb, fc)) <-> F.contramap(F.sum(F.product(fa, fb), F.product(fa, fc)))({ - case (a, Left(b)) => Left((a, b)) + case (a, Left(b)) => Left((a, b)) case (a, Right(c)) => Right((a, c)) }) } diff --git a/tests/src/test/scala/cats/tests/KleisliSuite.scala b/tests/src/test/scala/cats/tests/KleisliSuite.scala index 03e0f30b99..7c691ee52e 100644 --- a/tests/src/test/scala/cats/tests/KleisliSuite.scala +++ b/tests/src/test/scala/cats/tests/KleisliSuite.scala @@ -110,7 +110,9 @@ class KleisliSuite extends CatsSuite { ) checkAll( "Decidable[Kleisli[Option, Int, ?]]", - SerializableTests.serializable[Decidable[Kleisli[Predicate, MiniInt, *]]](Decidable[Kleisli[Predicate, MiniInt, *]]) + SerializableTests.serializable[Decidable[Kleisli[Predicate, MiniInt, *]]]( + Decidable[Kleisli[Predicate, MiniInt, *]] + ) ) } diff --git a/tests/src/test/scala/cats/tests/NestedSuite.scala b/tests/src/test/scala/cats/tests/NestedSuite.scala index 375d4cb31f..3999dd2caf 100644 --- a/tests/src/test/scala/cats/tests/NestedSuite.scala +++ b/tests/src/test/scala/cats/tests/NestedSuite.scala @@ -105,11 +105,13 @@ class NestedSuite extends CatsSuite { { // Applicative + ContravariantMonoidal functor composition // implicit val isos = Isomorphisms.invariant[Nested[Option, Const[String, *], *]] - checkAll("Nested[Option, Const[String, *], *]", - ContravariantMonoidalTests[λ[α => Nested[Option, Const[String, *], α]]].contravariantMonoidal[Int, Int, Int] + checkAll( + "Nested[Option, Const[String, *], *]", + ContravariantMonoidalTests[λ[α => Nested[Option, Const[String, *], α]]].contravariantMonoidal[Int, Int, Int] ) - checkAll("ContravariantMonoidal[Nested[Option, Const[String, *], *]", - SerializableTests.serializable(ContravariantMonoidal[λ[α => Nested[Option, Const[String, *], α]]]) + checkAll( + "ContravariantMonoidal[Nested[Option, Const[String, *], *]", + SerializableTests.serializable(ContravariantMonoidal[λ[α => Nested[Option, Const[String, *], α]]]) ) } diff --git a/tests/src/test/scala/cats/tests/OptionTSuite.scala b/tests/src/test/scala/cats/tests/OptionTSuite.scala index a89315a566..6cbcdfdbe3 100644 --- a/tests/src/test/scala/cats/tests/OptionTSuite.scala +++ b/tests/src/test/scala/cats/tests/OptionTSuite.scala @@ -104,9 +104,7 @@ class OptionTSuite extends CatsSuite { ) checkAll("OptionT[Predicate, MiniInt]", DecidableTests[OptionT[Predicate, *]].decidable[MiniInt, MiniInt, MiniInt]) - checkAll("Decidable[OptionT[Predicate, MiniInt]]", - SerializableTests.serializable(Decidable[OptionT[Predicate, *]]) - ) + checkAll("Decidable[OptionT[Predicate, MiniInt]]", SerializableTests.serializable(Decidable[OptionT[Predicate, *]])) // F has a ContravariantMonoidal checkAll("OptionT[Const[String, *], Int]", From ea48c089a28e1464f08594e8a56badf24b59644c Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 28 Jul 2020 11:26:31 -0700 Subject: [PATCH 33/87] Improve some instances, drop the product sum law --- core/src/main/scala/cats/data/OptionT.scala | 27 ++++++++++--------- .../src/main/scala/cats/instances/order.scala | 7 ++--- .../main/scala/cats/instances/ordering.scala | 7 ++--- .../main/scala/cats/laws/DecidableLaws.scala | 7 ----- 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index abbaeea411..f9cf01ea38 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -499,14 +499,19 @@ private trait OptionTMonadError[F[_], E] extends MonadError[OptionT[F, *], E] wi private trait OptionTDecidable[F[_]] extends Decidable[OptionT[F, *]] with OptionTContravariantMonoidal[F] { def F: Decidable[F] - def sum[A, B](fa: OptionT[F, A], fb: OptionT[F, B]): OptionT[F, Either[A, B]] = - OptionT( - F.decide(fa.value, fb.value)({ - case Some(Right(b)) => Right(Option(b)) - case Some(Left(a)) => Left(Option(a)) - case None => Left(None) - }) - ) + override def decide[A, B, C](fa: OptionT[F, A], fb: OptionT[F, B])(f: C => Either[A, B]): OptionT[F, C] = + OptionT( + F.contramap(F.product(fa.value, fb.value))(c => + c.map(f) + .fold[(Option[A], Option[B])]((None, None))( + _.fold( + b => (Some(b), None), + c => (None, Some(c)) + ))) + ) + + override def sum[A, B](fa: OptionT[F, A], fb: OptionT[F, B]): OptionT[F, Either[A, B]] = + decide(fa, fb)(identity) override def zero[A]: OptionT[F, INothing] = OptionT(F.trivial[Option[INothing]]) } @@ -521,12 +526,10 @@ private trait OptionTContravariantMonoidal[F[_]] extends ContravariantMonoidal[O override def product[A, B](fa: OptionT[F, A], fb: OptionT[F, B]): OptionT[F, (A, B)] = OptionT( - F.contramap(F.product(fa.value, fb.value))((t: Option[(A, B)]) => - t match { + F.contramap(F.product(fa.value, fb.value))({ case Some((x, y)) => (Some(x), Some(y)) case None => (None, None) - } - ) + }) ) } diff --git a/core/src/main/scala/cats/instances/order.scala b/core/src/main/scala/cats/instances/order.scala index 5367465b5a..e9173a9b82 100644 --- a/core/src/main/scala/cats/instances/order.scala +++ b/core/src/main/scala/cats/instances/order.scala @@ -38,9 +38,10 @@ trait OrderInstances extends kernel.instances.OrderInstances { if (y.isRight) (x, y).mapN(fb.compare).toOption.get else 1 - else if (y.isLeft) - (x.swap, y.swap).mapN(fa.compare).toOption.get - else -1 + else + if (y.isLeft) + (x.swap, y.swap).mapN(fa.compare).toOption.get + else -1 } override def zero[A]: Order[INothing] = Order.by(_ => ()) diff --git a/core/src/main/scala/cats/instances/ordering.scala b/core/src/main/scala/cats/instances/ordering.scala index b2239839fc..26e982aa5e 100644 --- a/core/src/main/scala/cats/instances/ordering.scala +++ b/core/src/main/scala/cats/instances/ordering.scala @@ -32,9 +32,10 @@ trait OrderingInstances { if (y.isRight) (x, y).mapN(fb.compare).toOption.get else 1 - else if (y.isLeft) - (x.swap, y.swap).mapN(fa.compare).toOption.get - else -1 + else + if (y.isLeft) + (x.swap, y.swap).mapN(fa.compare).toOption.get + else -1 } override def zero[A]: Ordering[INothing] = Ordering.by(_ => ()) diff --git a/laws/src/main/scala/cats/laws/DecidableLaws.scala b/laws/src/main/scala/cats/laws/DecidableLaws.scala index fd47776209..fa13b6e8f5 100644 --- a/laws/src/main/scala/cats/laws/DecidableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecidableLaws.scala @@ -30,13 +30,6 @@ trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { g.andThen(Right.apply) ) ) <-> F.sum(F.contramap(fa)(f), F.contramap(fb)(g)) - - def decidableRightDistributivitySum[A, B, C](fa: F[A], fb: F[B], fc: F[C]): IsEq[F[(A, Either[B, C])]] = - F.product(fa, F.sum(fb, fc)) <-> - F.contramap(F.sum(F.product(fa, fb), F.product(fa, fc)))({ - case (a, Left(b)) => Left((a, b)) - case (a, Right(c)) => Right((a, c)) - }) } object DecidableLaws { From a0325e8514e471224af705336b473b501d798134 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 28 Jul 2020 11:32:54 -0700 Subject: [PATCH 34/87] Fix laws references --- laws/src/main/scala/cats/laws/discipline/DecidableTests.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala index 074647d32f..6855df7df5 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala @@ -36,9 +36,7 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { "decidable sum associativity" -> forAll(laws.decidableSumAssociativity[A, B, C] _), "decidable right distributivity" -> - forAll(laws.decidableRightDistributivity[A, B, C] _), - "dedicable right sum distributivituy" -> - forAll(laws.decidableRightDistributivitySum[A, B, C] _) + forAll(laws.decidableRightDistributivity[A, B, C] _) ) } } From c8ff7b87c735df0112d83300397c8725c04239bf Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 28 Jul 2020 11:43:26 -0700 Subject: [PATCH 35/87] Add back law and weaken some instances --- .../main/scala-2.12/cats/instances/all.scala | 2 - .../scala-2.12/cats/instances/package.scala | 4 +- core/src/main/scala/cats/Invariant.scala | 9 ++-- core/src/main/scala/cats/Semigroupal.scala | 8 ++-- core/src/main/scala/cats/data/OptionT.scala | 29 ++---------- .../src/main/scala/cats/instances/order.scala | 45 ------------------- .../main/scala/cats/instances/ordering.scala | 38 ---------------- .../main/scala/cats/laws/DecidableLaws.scala | 7 +++ .../cats/laws/discipline/DecidableTests.scala | 4 +- .../test/scala/cats/tests/OrderSuite.scala | 7 ++- .../test/scala/cats/tests/OrderingSuite.scala | 4 +- 11 files changed, 28 insertions(+), 129 deletions(-) diff --git a/core/src/main/scala-2.12/cats/instances/all.scala b/core/src/main/scala-2.12/cats/instances/all.scala index daee3fb9b1..1b418511f0 100644 --- a/core/src/main/scala-2.12/cats/instances/all.scala +++ b/core/src/main/scala-2.12/cats/instances/all.scala @@ -50,8 +50,6 @@ trait AllInstancesBinCompat0 with Tuple2InstancesBinCompat0 with EqInstancesBinCompat0 with EquivInstancesBinCompat0 - with OrderInstancesBinCompat0 - with OrderingInstancesBinCompat0 trait AllInstancesBinCompat1 extends OptionInstancesBinCompat0 diff --git a/core/src/main/scala-2.12/cats/instances/package.scala b/core/src/main/scala-2.12/cats/instances/package.scala index 191fa46848..13ed2aedd1 100644 --- a/core/src/main/scala-2.12/cats/instances/package.scala +++ b/core/src/main/scala-2.12/cats/instances/package.scala @@ -24,8 +24,8 @@ package object instances { object long extends LongInstances object option extends OptionInstances with OptionInstancesBinCompat0 object map extends MapInstances with MapInstancesBinCompat0 with MapInstancesBinCompat1 - object order extends OrderInstances with OrderInstancesBinCompat0 - object ordering extends OrderingInstances with OrderingInstancesBinCompat0 + object order extends OrderInstances + object ordering extends OrderingInstances object parallel extends ParallelInstances object partialOrder extends PartialOrderInstances object partialOrdering extends PartialOrderingInstances diff --git a/core/src/main/scala/cats/Invariant.scala b/core/src/main/scala/cats/Invariant.scala index ad18bbd738..036fc5308b 100644 --- a/core/src/main/scala/cats/Invariant.scala +++ b/core/src/main/scala/cats/Invariant.scala @@ -141,14 +141,15 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn implicit def catsInvariantSemigroupalForMonoid: InvariantSemigroupal[Monoid] = cats.instances.invariant.catsSemigroupalForMonoid + implicit def catsContravariantMonoidalForOrder: ContravariantMonoidal[Order] = + cats.instances.order.catsContravariantMonoidalForOrder + implicit def catsContravariantMonoidalForOrdering: ContravariantMonoidal[Ordering] = + cats.instances.ordering.catsContravariantMonoidalForOrdering + implicit def catsDecidableForEquiv: Decidable[Equiv] = cats.instances.equiv.catsDecidableForEquiv implicit def catsDecidableForEq: Decidable[Eq] = cats.instances.eq.catsDecidableForEq - implicit def catsDecidableForOrder: Decidable[Order] = - cats.instances.order.catsDecidableForOrder - implicit def catsDecidableForOrdering: Decidable[Ordering] = - cats.instances.ordering.catsDecidableForOrdering implicit def catsDecidableForPredicate: Decidable[* => Boolean] = cats.instances.function.catsStdDecidableForPredicate diff --git a/core/src/main/scala/cats/Semigroupal.scala b/core/src/main/scala/cats/Semigroupal.scala index cb140ccd0f..0b0b665345 100644 --- a/core/src/main/scala/cats/Semigroupal.scala +++ b/core/src/main/scala/cats/Semigroupal.scala @@ -62,16 +62,16 @@ object Semigroupal extends ScalaVersionSpecificSemigroupalInstances with Semigro cats.instances.sortedMap.catsStdInstancesForSortedMap[K] implicit def catsSemigroupalForFunction1[A]: Semigroupal[A => *] = cats.instances.function.catsStdMonadForFunction1[A] -// implicit def catsSemigroupalForFunction1Contravariant[R: Monoid]: Semigroupal[* => R] = -// cats.instances.function.catsStdContravariantMonoidalForFunction1[R] + implicit def catsSemigroupalForFunction1Contravariant[R: Monoid]: Semigroupal[* => R] = + cats.instances.function.catsStdContravariantMonoidalForFunction1[R] implicit def catsSemigroupalForFunction0: Semigroupal[Function0] = cats.instances.function.catsStdBimonadForFunction0 - implicit val catsSemigroupalForOrder: Semigroupal[Order] = cats.instances.order.catsDecidableForOrder + implicit val catsSemigroupalForOrder: Semigroupal[Order] = cats.instances.order.catsContravariantMonoidalForOrder implicit val catsSemigroupalForPartialOrder: Semigroupal[PartialOrder] = cats.instances.partialOrder.catsContravariantMonoidalForPartialOrder implicit val catsSemigroupalForOrdering: Semigroupal[Ordering] = - cats.instances.ordering.catsDecidableForOrdering + cats.instances.ordering.catsContravariantMonoidalForOrdering implicit val catsSemigroupalForPartialOrdering: Semigroupal[PartialOrdering] = cats.instances.partialOrdering.catsContravariantMonoidalForPartialOrdering implicit val catsSemigroupalForEq: Semigroupal[Eq] = cats.instances.eq.catsDecidableForEq diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index f9cf01ea38..5b22d14d11 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -385,9 +385,6 @@ sealed abstract private[data] class OptionTInstances0 extends OptionTInstances1 implicit val F = F0 } - implicit def catsDataDecidableForOptionT[F[_]](implicit F0: Decidable[F]): Decidable[OptionT[F, *]] = - new OptionTDecidable[F] { implicit val F = F0 } - implicit def catsDataMonoidKForOptionT[F[_]](implicit F0: Monad[F]): MonoidK[OptionT[F, *]] = new OptionTMonoidK[F] { implicit val F = F0 } @@ -496,26 +493,6 @@ private trait OptionTMonadError[F[_], E] extends MonadError[OptionT[F, *], E] wi OptionT(F.handleErrorWith(fa.value)(f(_).value)) } -private trait OptionTDecidable[F[_]] extends Decidable[OptionT[F, *]] with OptionTContravariantMonoidal[F] { - def F: Decidable[F] - - override def decide[A, B, C](fa: OptionT[F, A], fb: OptionT[F, B])(f: C => Either[A, B]): OptionT[F, C] = - OptionT( - F.contramap(F.product(fa.value, fb.value))(c => - c.map(f) - .fold[(Option[A], Option[B])]((None, None))( - _.fold( - b => (Some(b), None), - c => (None, Some(c)) - ))) - ) - - override def sum[A, B](fa: OptionT[F, A], fb: OptionT[F, B]): OptionT[F, Either[A, B]] = - decide(fa, fb)(identity) - - override def zero[A]: OptionT[F, INothing] = OptionT(F.trivial[Option[INothing]]) -} - private trait OptionTContravariantMonoidal[F[_]] extends ContravariantMonoidal[OptionT[F, *]] { def F: ContravariantMonoidal[F] @@ -527,9 +504,9 @@ private trait OptionTContravariantMonoidal[F[_]] extends ContravariantMonoidal[O override def product[A, B](fa: OptionT[F, A], fb: OptionT[F, B]): OptionT[F, (A, B)] = OptionT( F.contramap(F.product(fa.value, fb.value))({ - case Some((x, y)) => (Some(x), Some(y)) - case None => (None, None) - }) + case Some((x, y)) => (Some(x), Some(y)) + case None => (None, None) + }) ) } diff --git a/core/src/main/scala/cats/instances/order.scala b/core/src/main/scala/cats/instances/order.scala index e9173a9b82..675d68ae61 100644 --- a/core/src/main/scala/cats/instances/order.scala +++ b/core/src/main/scala/cats/instances/order.scala @@ -1,54 +1,9 @@ package cats package instances -import cats.data.INothing -import cats.instances.either._ -import cats.syntax.apply._ import cats.kernel.instances.unit._ trait OrderInstances extends kernel.instances.OrderInstances { - implicit val catsDecidableForOrder: Decidable[Order] = - new Decidable[Order] { - - /** - * Provides trivial order - */ - def unit: Order[Unit] = Order[Unit] - - /** - * Derive an `Order` for `B` given an `Order[A]` and a function `B => A`. - * - * Note: resulting instances are law-abiding only when the functions used are injective (represent a one-to-one mapping) - */ - def contramap[A, B](fa: Order[A])(f: B => A): Order[B] = - Order.by(f)(fa) - - def product[A, B](fa: Order[A], fb: Order[B]): Order[(A, B)] = - new Order[(A, B)] { - def compare(x: (A, B), y: (A, B)): Int = { - val z = fa.compare(x._1, y._1) - if (z == 0) fb.compare(x._2, y._2) else z - } - } - - def sum[A, B](fa: Order[A], fb: Order[B]): Order[Either[A, B]] = - new Order[Either[A, B]] { - def compare(x: Either[A, B], y: Either[A, B]): Int = - if (x.isRight) - if (y.isRight) - (x, y).mapN(fb.compare).toOption.get - else 1 - else - if (y.isLeft) - (x.swap, y.swap).mapN(fa.compare).toOption.get - else -1 - } - - override def zero[A]: Order[INothing] = Order.by(_ => ()) - } -} - -private[instances] trait OrderInstancesBinCompat0 { implicit val catsContravariantMonoidalForOrder: ContravariantMonoidal[Order] = new ContravariantMonoidal[Order] { diff --git a/core/src/main/scala/cats/instances/ordering.scala b/core/src/main/scala/cats/instances/ordering.scala index 26e982aa5e..23cbd7e071 100644 --- a/core/src/main/scala/cats/instances/ordering.scala +++ b/core/src/main/scala/cats/instances/ordering.scala @@ -1,47 +1,9 @@ package cats package instances -import cats.data.INothing -import cats.instances.either._ -import cats.syntax.apply._ import cats.kernel.instances.unit._ trait OrderingInstances { - implicit val catsDecidableForOrdering: Decidable[Ordering] = - new Decidable[Ordering] { - - /** - * Note: resulting instances are law-abiding only when the functions used are injective (represent a one-to-one mapping) - */ - def unit: Ordering[Unit] = Order[Unit].toOrdering - - def contramap[A, B](fa: Ordering[A])(f: B => A): Ordering[B] = fa.on(f) - - def product[A, B](fa: Ordering[A], fb: Ordering[B]): Ordering[(A, B)] = - new Ordering[(A, B)] { - def compare(x: (A, B), y: (A, B)): Int = { - val z = fa.compare(x._1, y._1) - if (z == 0) fb.compare(x._2, y._2) else z - } - } - - def sum[A, B](fa: Ordering[A], fb: Ordering[B]): Ordering[Either[A, B]] = - new Ordering[Either[A, B]] { - def compare(x: Either[A, B], y: Either[A, B]): Int = - if (x.isRight) - if (y.isRight) - (x, y).mapN(fb.compare).toOption.get - else 1 - else - if (y.isLeft) - (x.swap, y.swap).mapN(fa.compare).toOption.get - else -1 - } - - override def zero[A]: Ordering[INothing] = Ordering.by(_ => ()) - } -} -private[instances] trait OrderingInstancesBinCompat0 { implicit val catsContravariantMonoidalForOrdering: ContravariantMonoidal[Ordering] = new ContravariantMonoidal[Ordering] { diff --git a/laws/src/main/scala/cats/laws/DecidableLaws.scala b/laws/src/main/scala/cats/laws/DecidableLaws.scala index fa13b6e8f5..fd47776209 100644 --- a/laws/src/main/scala/cats/laws/DecidableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecidableLaws.scala @@ -30,6 +30,13 @@ trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { g.andThen(Right.apply) ) ) <-> F.sum(F.contramap(fa)(f), F.contramap(fb)(g)) + + def decidableRightDistributivitySum[A, B, C](fa: F[A], fb: F[B], fc: F[C]): IsEq[F[(A, Either[B, C])]] = + F.product(fa, F.sum(fb, fc)) <-> + F.contramap(F.sum(F.product(fa, fb), F.product(fa, fc)))({ + case (a, Left(b)) => Left((a, b)) + case (a, Right(c)) => Right((a, c)) + }) } object DecidableLaws { diff --git a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala index 6855df7df5..074647d32f 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala @@ -36,7 +36,9 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { "decidable sum associativity" -> forAll(laws.decidableSumAssociativity[A, B, C] _), "decidable right distributivity" -> - forAll(laws.decidableRightDistributivity[A, B, C] _) + forAll(laws.decidableRightDistributivity[A, B, C] _), + "dedicable right sum distributivituy" -> + forAll(laws.decidableRightDistributivitySum[A, B, C] _) ) } } diff --git a/tests/src/test/scala/cats/tests/OrderSuite.scala b/tests/src/test/scala/cats/tests/OrderSuite.scala index 400ed7f5da..5f590243eb 100644 --- a/tests/src/test/scala/cats/tests/OrderSuite.scala +++ b/tests/src/test/scala/cats/tests/OrderSuite.scala @@ -3,7 +3,7 @@ package cats.tests import cats.{Contravariant, ContravariantMonoidal, Decidable, Invariant} import cats.kernel.{Order, PartialOrder} import cats.kernel.laws.discipline.{OrderTests, SerializableTests} -import cats.laws.discipline.{DecidableTests, MiniInt} +import cats.laws.discipline.{ContravariantMonoidalTests, DecidableTests, MiniInt} import cats.laws.discipline.arbitrary._ import cats.laws.discipline.eq._ import cats.syntax.order._ @@ -14,7 +14,6 @@ class OrderSuite extends CatsSuite { Invariant[Order] Contravariant[Order] ContravariantMonoidal[Order] - Decidable[Order] } checkAll("Int", OrderTests[Int].order) @@ -22,8 +21,8 @@ class OrderSuite extends CatsSuite { checkAll("Float", OrderTests[Float].order) checkAll("Long", OrderTests[Long].order) - checkAll("Order", DecidableTests[Order].decidable[MiniInt, Boolean, Boolean]) - checkAll("Decidable[Order]", SerializableTests.serializable(Decidable[Order])) + checkAll("Order", ContravariantMonoidalTests[Order].contravariantMonoidal[MiniInt, Boolean, Boolean]) + checkAll("Decidable[Order]", SerializableTests.serializable(ContravariantMonoidal[Order])) test("order ops syntax") { forAll { (i: Ord, j: Ord) => diff --git a/tests/src/test/scala/cats/tests/OrderingSuite.scala b/tests/src/test/scala/cats/tests/OrderingSuite.scala index 20ac3700fb..fc99856a12 100644 --- a/tests/src/test/scala/cats/tests/OrderingSuite.scala +++ b/tests/src/test/scala/cats/tests/OrderingSuite.scala @@ -11,13 +11,11 @@ class OrderingSuite extends CatsSuite { Semigroupal[Ordering] ContravariantSemigroupal[Ordering] ContravariantMonoidal[Ordering] - Decidable[Ordering] checkAll("Contravariant[Ordering]", ContravariantTests[Ordering].contravariant[MiniInt, Int, Boolean]) checkAll("Semigroupal[Ordering]", SemigroupalTests[Ordering].semigroupal[MiniInt, Boolean, Boolean]) checkAll("ContravariantMonoidal[Ordering]", ContravariantMonoidalTests[Ordering].contravariantMonoidal[MiniInt, Boolean, Boolean] ) - checkAll("Decidable[Ordering]", DecidableTests[Ordering].decidable[MiniInt, Boolean, Boolean]) - checkAll("Decidable[Ordering]", SerializableTests.serializable(Decidable[Ordering])) + checkAll("ContravariantMonoidal[Ordering]", SerializableTests.serializable(ContravariantMonoidal[Ordering])) } From 55bdd9192e2b924840783ba7c41c5924e7b21d55 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 28 Jul 2020 12:05:59 -0700 Subject: [PATCH 36/87] Fix a test --- tests/src/test/scala/cats/tests/OptionTSuite.scala | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/src/test/scala/cats/tests/OptionTSuite.scala b/tests/src/test/scala/cats/tests/OptionTSuite.scala index 6cbcdfdbe3..190a2dfdbb 100644 --- a/tests/src/test/scala/cats/tests/OptionTSuite.scala +++ b/tests/src/test/scala/cats/tests/OptionTSuite.scala @@ -98,14 +98,6 @@ class OptionTSuite extends CatsSuite { } { - // F has a Decidable - implicit val iso = SemigroupalTests.Isomorphisms.invariant[OptionT[Predicate, *]]( - OptionT.catsDataDecidableForOptionT(Predicate.decidablePredicate) - ) - - checkAll("OptionT[Predicate, MiniInt]", DecidableTests[OptionT[Predicate, *]].decidable[MiniInt, MiniInt, MiniInt]) - checkAll("Decidable[OptionT[Predicate, MiniInt]]", SerializableTests.serializable(Decidable[OptionT[Predicate, *]])) - // F has a ContravariantMonoidal checkAll("OptionT[Const[String, *], Int]", ContravariantMonoidalTests[OptionT[Const[String, *], *]].contravariantMonoidal[Int, Int, Int] From 692c3e05e45557b5e33184f74e17eb72be15ee5c Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 28 Jul 2020 13:54:56 -0700 Subject: [PATCH 37/87] Clean flags --- build.sbt | 3 --- 1 file changed, 3 deletions(-) diff --git a/build.sbt b/build.sbt index 8e67f9e469..97b8e18beb 100644 --- a/build.sbt +++ b/build.sbt @@ -815,9 +815,6 @@ def commonScalacOptions(scalaVersion: String, isDotty: Boolean) = "UTF-8", "-feature", "-unchecked", - //"-Ywarn-dead-code", - "-Ywarn-numeric-widen", - "-Ywarn-value-discard", "-Xfatal-warnings", "-deprecation" ) ++ (if (priorTo2_13(scalaVersion)) From 85d29ef296534fe493277187d1ea096820f703e5 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 28 Jul 2020 14:15:03 -0700 Subject: [PATCH 38/87] Clean some imports --- tests/src/test/scala/cats/tests/OrderSuite.scala | 4 ++-- tests/src/test/scala/cats/tests/OrderingSuite.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/src/test/scala/cats/tests/OrderSuite.scala b/tests/src/test/scala/cats/tests/OrderSuite.scala index 5f590243eb..e0847335e1 100644 --- a/tests/src/test/scala/cats/tests/OrderSuite.scala +++ b/tests/src/test/scala/cats/tests/OrderSuite.scala @@ -1,9 +1,9 @@ package cats.tests -import cats.{Contravariant, ContravariantMonoidal, Decidable, Invariant} +import cats.{Contravariant, ContravariantMonoidal, Invariant} import cats.kernel.{Order, PartialOrder} import cats.kernel.laws.discipline.{OrderTests, SerializableTests} -import cats.laws.discipline.{ContravariantMonoidalTests, DecidableTests, MiniInt} +import cats.laws.discipline.{ContravariantMonoidalTests, MiniInt} import cats.laws.discipline.arbitrary._ import cats.laws.discipline.eq._ import cats.syntax.order._ diff --git a/tests/src/test/scala/cats/tests/OrderingSuite.scala b/tests/src/test/scala/cats/tests/OrderingSuite.scala index fc99856a12..dc0221e62d 100644 --- a/tests/src/test/scala/cats/tests/OrderingSuite.scala +++ b/tests/src/test/scala/cats/tests/OrderingSuite.scala @@ -1,6 +1,6 @@ package cats.tests -import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal, Decidable, Invariant, Semigroupal} +import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal, Invariant, Semigroupal} import cats.laws.discipline.arbitrary._ import cats.laws.discipline._ import cats.laws.discipline.eq._ From beb03d60ea78a2c919372fbaed8ccd15d392b090 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 28 Jul 2020 14:29:38 -0700 Subject: [PATCH 39/87] Improve binary compat --- core/src/main/scala/cats/instances/eq.scala | 34 +++++++++--------- .../src/main/scala/cats/instances/equiv.scala | 36 +++++++++---------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index 64206b4bbe..bff14a0e25 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -6,8 +6,8 @@ import cats.instances.either._ import cats.syntax.apply._ trait EqInstances extends kernel.instances.EqInstances { - implicit val catsDecidableForEq: Decidable[Eq] = - new Decidable[Eq] { + implicit val catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = + new ContravariantMonoidal[Eq] { /** * Defaults to the trivial equivalence relation @@ -27,25 +27,12 @@ trait EqInstances extends kernel.instances.EqInstances { Eq.instance { (left, right) => fa.eqv(left._1, right._1) && fb.eqv(left._2, right._2) } - - def sum[A, B](fa: Eq[A], fb: Eq[B]): Eq[Either[A, B]] = - Eq.instance { (left, right) => - if (left.isRight) - if (right.isRight) - (left, right).mapN(fb.eqv).toOption.get - else false - else if (right.isLeft) - (left.swap, right.swap).mapN(fa.eqv).toOption.get - else false - } - - override def zero[A]: Eq[INothing] = Eq.allEqual[INothing] } } private[instances] trait EqInstancesBinCompat0 { - implicit val catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = - new ContravariantMonoidal[Eq] { + implicit val catsDecidableForEq: Decidable[Eq] = + new Decidable[Eq] { /** * Defaults to the trivial equivalence relation @@ -65,5 +52,18 @@ private[instances] trait EqInstancesBinCompat0 { Eq.instance { (left, right) => fa.eqv(left._1, right._1) && fb.eqv(left._2, right._2) } + + def sum[A, B](fa: Eq[A], fb: Eq[B]): Eq[Either[A, B]] = + Eq.instance { (left, right) => + if (left.isRight) + if (right.isRight) + (left, right).mapN(fb.eqv).toOption.get + else false + else if (right.isLeft) + (left.swap, right.swap).mapN(fa.eqv).toOption.get + else false + } + + override def zero[A]: Eq[INothing] = Eq.allEqual[INothing] } } diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index a7f1555708..e06e7b7265 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -6,8 +6,8 @@ import cats.instances.either._ import cats.syntax.apply._ trait EquivInstances { - implicit val catsDecidableForEquiv: Decidable[Equiv] = - new Decidable[Equiv] { + implicit val catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = + new ContravariantMonoidal[Equiv] { /** * Defaults to trivially contracting the type @@ -34,26 +34,12 @@ trait EquivInstances { def equiv(l: (A, B), r: (A, B)): Boolean = fa.equiv(l._1, r._1) && fb.equiv(l._2, r._2) } - - def sum[A, B](fa: Equiv[A], fb: Equiv[B]): Equiv[Either[A, B]] = - new Equiv[Either[A, B]] { - def equiv(x: Either[A, B], y: Either[A, B]): Boolean = - if (x.isRight) - if (y.isRight) - (x, y).mapN(fb.equiv).toOption.get - else false - else if (y.isLeft) - (x.swap, y.swap).mapN(fa.equiv).toOption.get - else false - } - - override def zero[A]: Equiv[INothing] = Equiv.by(_ => ()) } } private[instances] trait EquivInstancesBinCompat0 { - implicit val catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = - new ContravariantMonoidal[Equiv] { + implicit val catsDecidableForEquiv: Decidable[Equiv] = + new Decidable[Equiv] { /** * Defaults to trivially contracting the type @@ -80,5 +66,19 @@ private[instances] trait EquivInstancesBinCompat0 { def equiv(l: (A, B), r: (A, B)): Boolean = fa.equiv(l._1, r._1) && fb.equiv(l._2, r._2) } + + def sum[A, B](fa: Equiv[A], fb: Equiv[B]): Equiv[Either[A, B]] = + new Equiv[Either[A, B]] { + def equiv(x: Either[A, B], y: Either[A, B]): Boolean = + if (x.isRight) + if (y.isRight) + (x, y).mapN(fb.equiv).toOption.get + else false + else if (y.isLeft) + (x.swap, y.swap).mapN(fa.equiv).toOption.get + else false + } + + override def zero[A]: Equiv[INothing] = Equiv.by(_ => ()) } } From dccb090c78065cd9ff2347d0b73ff98578dba619 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 28 Jul 2020 14:43:58 -0700 Subject: [PATCH 40/87] Try to fix some mima issues --- .../main/scala-2.12/cats/instances/all.scala | 2 - .../scala-2.12/cats/instances/package.scala | 4 +- core/src/main/scala/cats/instances/eq.scala | 38 +++++++++--------- .../src/main/scala/cats/instances/equiv.scala | 40 +++++++++---------- 4 files changed, 41 insertions(+), 43 deletions(-) diff --git a/core/src/main/scala-2.12/cats/instances/all.scala b/core/src/main/scala-2.12/cats/instances/all.scala index 1b418511f0..fbeb46721d 100644 --- a/core/src/main/scala-2.12/cats/instances/all.scala +++ b/core/src/main/scala-2.12/cats/instances/all.scala @@ -48,8 +48,6 @@ trait AllInstances trait AllInstancesBinCompat0 extends FunctionInstancesBinCompat0 with Tuple2InstancesBinCompat0 - with EqInstancesBinCompat0 - with EquivInstancesBinCompat0 trait AllInstancesBinCompat1 extends OptionInstancesBinCompat0 diff --git a/core/src/main/scala-2.12/cats/instances/package.scala b/core/src/main/scala-2.12/cats/instances/package.scala index 13ed2aedd1..15afd68f17 100644 --- a/core/src/main/scala-2.12/cats/instances/package.scala +++ b/core/src/main/scala-2.12/cats/instances/package.scala @@ -11,8 +11,8 @@ package object instances { object double extends DoubleInstances object duration extends CoreDurationInstances with DurationInstances object either extends EitherInstances - object eq extends EqInstances with EqInstancesBinCompat0 - object equiv extends EquivInstances with EquivInstancesBinCompat0 + object eq extends EqInstances + object equiv extends EquivInstances object float extends FloatInstances object finiteDuration extends CoreFiniteDurationInstances with FiniteDurationInstances object function extends FunctionInstances with FunctionInstancesBinCompat0 diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index bff14a0e25..0e05c6c122 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -5,9 +5,9 @@ import cats.data.INothing import cats.instances.either._ import cats.syntax.apply._ -trait EqInstances extends kernel.instances.EqInstances { - implicit val catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = - new ContravariantMonoidal[Eq] { +trait EqInstances extends kernel.instances.EqInstances with EqInstances0 { + implicit val catsDecidableForEq: Decidable[Eq] = + new Decidable[Eq] { /** * Defaults to the trivial equivalence relation @@ -27,12 +27,25 @@ trait EqInstances extends kernel.instances.EqInstances { Eq.instance { (left, right) => fa.eqv(left._1, right._1) && fb.eqv(left._2, right._2) } + + def sum[A, B](fa: Eq[A], fb: Eq[B]): Eq[Either[A, B]] = + Eq.instance { (left, right) => + if (left.isRight) + if (right.isRight) + (left, right).mapN(fb.eqv).toOption.get + else false + else if (right.isLeft) + (left.swap, right.swap).mapN(fa.eqv).toOption.get + else false + } + + override def zero[A]: Eq[INothing] = Eq.allEqual[INothing] } } -private[instances] trait EqInstancesBinCompat0 { - implicit val catsDecidableForEq: Decidable[Eq] = - new Decidable[Eq] { +private[instances] trait EqInstances0 { + implicit def catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = + new ContravariantMonoidal[Eq] { /** * Defaults to the trivial equivalence relation @@ -52,18 +65,5 @@ private[instances] trait EqInstancesBinCompat0 { Eq.instance { (left, right) => fa.eqv(left._1, right._1) && fb.eqv(left._2, right._2) } - - def sum[A, B](fa: Eq[A], fb: Eq[B]): Eq[Either[A, B]] = - Eq.instance { (left, right) => - if (left.isRight) - if (right.isRight) - (left, right).mapN(fb.eqv).toOption.get - else false - else if (right.isLeft) - (left.swap, right.swap).mapN(fa.eqv).toOption.get - else false - } - - override def zero[A]: Eq[INothing] = Eq.allEqual[INothing] } } diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index e06e7b7265..6215530006 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -5,9 +5,9 @@ import cats.data.INothing import cats.instances.either._ import cats.syntax.apply._ -trait EquivInstances { - implicit val catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = - new ContravariantMonoidal[Equiv] { +trait EquivInstances extends EquivInstances0 { + implicit val catsDecidableForEquiv: Decidable[Equiv] = + new Decidable[Equiv] { /** * Defaults to trivially contracting the type @@ -34,12 +34,26 @@ trait EquivInstances { def equiv(l: (A, B), r: (A, B)): Boolean = fa.equiv(l._1, r._1) && fb.equiv(l._2, r._2) } + + def sum[A, B](fa: Equiv[A], fb: Equiv[B]): Equiv[Either[A, B]] = + new Equiv[Either[A, B]] { + def equiv(x: Either[A, B], y: Either[A, B]): Boolean = + if (x.isRight) + if (y.isRight) + (x, y).mapN(fb.equiv).toOption.get + else false + else if (y.isLeft) + (x.swap, y.swap).mapN(fa.equiv).toOption.get + else false + } + + override def zero[A]: Equiv[INothing] = Equiv.by(_ => ()) } } -private[instances] trait EquivInstancesBinCompat0 { - implicit val catsDecidableForEquiv: Decidable[Equiv] = - new Decidable[Equiv] { +private[instances] trait EquivInstances0 { + implicit def catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = + new ContravariantMonoidal[Equiv] { /** * Defaults to trivially contracting the type @@ -66,19 +80,5 @@ private[instances] trait EquivInstancesBinCompat0 { def equiv(l: (A, B), r: (A, B)): Boolean = fa.equiv(l._1, r._1) && fb.equiv(l._2, r._2) } - - def sum[A, B](fa: Equiv[A], fb: Equiv[B]): Equiv[Either[A, B]] = - new Equiv[Either[A, B]] { - def equiv(x: Either[A, B], y: Either[A, B]): Boolean = - if (x.isRight) - if (y.isRight) - (x, y).mapN(fb.equiv).toOption.get - else false - else if (y.isLeft) - (x.swap, y.swap).mapN(fa.equiv).toOption.get - else false - } - - override def zero[A]: Equiv[INothing] = Equiv.by(_ => ()) } } From d88f178472b8e9f9d9ed2e7f5ace584b2f5b5e0f Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 28 Jul 2020 14:49:20 -0700 Subject: [PATCH 41/87] Baffling that that works --- core/src/main/scala/cats/instances/eq.scala | 2 +- core/src/main/scala/cats/instances/equiv.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index 0e05c6c122..fe5ef1b6c7 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -6,7 +6,7 @@ import cats.instances.either._ import cats.syntax.apply._ trait EqInstances extends kernel.instances.EqInstances with EqInstances0 { - implicit val catsDecidableForEq: Decidable[Eq] = + implicit def catsDecidableForEq: Decidable[Eq] = new Decidable[Eq] { /** diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index 6215530006..e46c7d8b7b 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -6,7 +6,7 @@ import cats.instances.either._ import cats.syntax.apply._ trait EquivInstances extends EquivInstances0 { - implicit val catsDecidableForEquiv: Decidable[Equiv] = + implicit def catsDecidableForEquiv: Decidable[Equiv] = new Decidable[Equiv] { /** From d67ee5c5c4d4de7c3ed41b02050dcf64a531df46 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 28 Jul 2020 18:26:28 -0700 Subject: [PATCH 42/87] Formatting --- core/src/main/scala-2.12/cats/instances/all.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/src/main/scala-2.12/cats/instances/all.scala b/core/src/main/scala-2.12/cats/instances/all.scala index fbeb46721d..e9451a80be 100644 --- a/core/src/main/scala-2.12/cats/instances/all.scala +++ b/core/src/main/scala-2.12/cats/instances/all.scala @@ -45,9 +45,7 @@ trait AllInstances with VectorInstances with PartialFunctionInstances -trait AllInstancesBinCompat0 - extends FunctionInstancesBinCompat0 - with Tuple2InstancesBinCompat0 +trait AllInstancesBinCompat0 extends FunctionInstancesBinCompat0 with Tuple2InstancesBinCompat0 trait AllInstancesBinCompat1 extends OptionInstancesBinCompat0 From b64f3f82cf5c9b40a630bb47fcb24cf52a3e82fd Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Sun, 26 Jun 2022 11:16:00 -1000 Subject: [PATCH 43/87] Fix merge --- core/src/main/scala/cats/Decidable.scala | 12 +----------- core/src/main/scala/cats/Invariant.scala | 7 ++----- core/src/main/scala/cats/data/Kleisli.scala | 2 +- core/src/main/scala/cats/data/Op.scala | 12 ++++++------ core/src/main/scala/cats/data/OptionT.scala | 2 +- core/src/main/scala/cats/data/WriterT.scala | 2 +- .../test/scala/cats/tests/ContravariantSuite.scala | 1 + .../shared/src/test/scala/cats/tests/EqSuite.scala | 6 +++--- .../src/test/scala/cats/tests/EquivSuite.scala | 2 +- .../src/test/scala/cats/tests/KleisliSuite.scala | 13 ++++++------- .../src/test/scala/cats/tests/OrderSuite.scala | 6 +----- .../src/test/scala/cats/tests/OrderingSuite.scala | 4 +--- .../src/test/scala/cats/tests/Predicate.scala | 0 13 files changed, 25 insertions(+), 44 deletions(-) rename tests/{ => shared}/src/test/scala/cats/tests/Predicate.scala (100%) diff --git a/core/src/main/scala/cats/Decidable.scala b/core/src/main/scala/cats/Decidable.scala index 08a88465c9..94ff6b2dd5 100644 --- a/core/src/main/scala/cats/Decidable.scala +++ b/core/src/main/scala/cats/Decidable.scala @@ -1,7 +1,6 @@ package cats import cats.data.INothing -import simulacrum.typeclass import scala.annotation.implicitNotFound @@ -18,7 +17,7 @@ import scala.annotation.implicitNotFound * https://hackage.haskell.org/package/contravariant-1.4/docs/Data-Functor-Contravariant-Divisible.html#g:2 */ @implicitNotFound("Could not find an instance of Decidable for ${F}") -@typeclass trait Decidable[F[_]] extends ContravariantMonoidal[F] { +trait Decidable[F[_]] extends ContravariantMonoidal[F] { def sum[A, B](fa: F[A], fb: F[B]): F[Either[A, B]] def decide[A, B, C](fa: F[A], fb: F[B])(f: C => Either[A, B]): F[C] = @@ -30,10 +29,6 @@ import scala.annotation.implicitNotFound } object Decidable { - /* ======================================================================== */ - /* THE FOLLOWING CODE IS MANAGED BY SIMULACRUM; PLEASE DO NOT EDIT!!!! */ - /* ======================================================================== */ - /** * Summon an instance of [[Decidable]] for `F`. */ @@ -73,9 +68,4 @@ object Decidable { } @deprecated("Use cats.syntax object imports", "2.2.0") object nonInheritedOps extends ToDecidableOps - - /* ======================================================================== */ - /* END OF SIMULACRUM-MANAGED CODE */ - /* ======================================================================== */ - } diff --git a/core/src/main/scala/cats/Invariant.scala b/core/src/main/scala/cats/Invariant.scala index 33c9a05e74..d3dd3f187c 100644 --- a/core/src/main/scala/cats/Invariant.scala +++ b/core/src/main/scala/cats/Invariant.scala @@ -147,7 +147,6 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn implicit def catsFlatMapForSortedMap[K]: FlatMap[SortedMap[K, *]] = cats.instances.sortedMap.catsStdInstancesForSortedMap[K] implicit def catsBimonadForFunction0: Bimonad[Function0] = cats.instances.function.catsStdBimonadForFunction0 - implicit def catsMonadForFunction1[I]: Monad[I => *] = cats.instances.function.catsStdMonadForFunction1[I] implicit def catsContravariantMonoidalForFunction1[R: Monoid]: ContravariantMonoidal[* => R] = cats.instances.function.catsStdContravariantMonoidalForFunction1[R] implicit def catsFunctorForPair: Functor[λ[P => (P, P)]] = cats.instances.tuple.catsDataFunctorForPair @@ -173,6 +172,8 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn cats.instances.order.catsContravariantMonoidalForOrder implicit def catsContravariantMonoidalForPartialOrder: ContravariantMonoidal[PartialOrder] = cats.instances.partialOrder.catsContravariantMonoidalForPartialOrder + implicit def catsContravariantMonoidalForOrdering: ContravariantMonoidal[Ordering] = + cats.instances.ordering.catsContravariantMonoidalForOrdering implicit def catsContravariantMonoidalForPartialOrdering: ContravariantMonoidal[PartialOrdering] = cats.instances.partialOrdering.catsContravariantMonoidalForPartialOrdering implicit def catsContravariantForHash: Contravariant[Hash] = @@ -190,10 +191,6 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn implicit def catsInvariantForFractional: Invariant[Fractional] = cats.instances.invariant.catsInvariantForFractional - implicit def catsContravariantMonoidalForOrder: ContravariantMonoidal[Order] = - cats.instances.order.catsContravariantMonoidalForOrder - implicit def catsContravariantMonoidalForOrdering: ContravariantMonoidal[Ordering] = - cats.instances.ordering.catsContravariantMonoidalForOrdering implicit def catsDecidableForEquiv: Decidable[Equiv] = cats.instances.equiv.catsDecidableForEquiv diff --git a/core/src/main/scala/cats/data/Kleisli.scala b/core/src/main/scala/cats/data/Kleisli.scala index 05986606bf..67d7b7e80b 100644 --- a/core/src/main/scala/cats/data/Kleisli.scala +++ b/core/src/main/scala/cats/data/Kleisli.scala @@ -373,7 +373,7 @@ sealed abstract private[data] class KleisliInstances0 extends KleisliInstances0_ implicit def catsDataDecidableForKleisli[F[_], A](implicit F0: Decidable[F] - ): Decidable[Kleisli[F, A, ?]] = + ): Decidable[Kleisli[F, A, *]] = new KleisliDecidable[F, A] { def F: Decidable[F] = F0 } } diff --git a/core/src/main/scala/cats/data/Op.scala b/core/src/main/scala/cats/data/Op.scala index d896e5e5a8..7f0a6e8ab6 100644 --- a/core/src/main/scala/cats/data/Op.scala +++ b/core/src/main/scala/cats/data/Op.scala @@ -44,7 +44,7 @@ sealed abstract private[data] class OpInstances extends OpInstances0 { implicit def catsDataDecidableForOp[Arr[_, _], R](implicit ArrC: ArrowChoice[Arr], monn: Monoid[R] - ): Decidable[Op[Arr, R, ?]] = + ): Decidable[Op[Arr, R, *]] = new OpDecidable[Arr, R] { def Arr: ArrowChoice[Arr] = ArrC def M: Monoid[R] = monn @@ -65,12 +65,12 @@ sealed abstract private[data] class OpInstances0 { implicit def catsDataContravariantMonoidalForOp[Arr[_, _], R](implicit ArrC: Arrow[Arr], M0: Monoid[R] - ): ContravariantMonoidal[Op[Arr, R, ?]] = + ): ContravariantMonoidal[Op[Arr, R, *]] = new OpContravariantMonoidal[Arr, R] { def Arr = ArrC; def M = M0 } } sealed abstract private[data] class OpInstances1 { - implicit def catsDataContravariantForOp[Arr[_, _], R](implicit ArrC: Arrow[Arr]): Contravariant[Op[Arr, R, ?]] = + implicit def catsDataContravariantForOp[Arr[_, _], R](implicit ArrC: Arrow[Arr]): Contravariant[Op[Arr, R, *]] = new OpContravariant[Arr, R] { def Arr = ArrC } } @@ -87,7 +87,7 @@ private[data] trait OpCompose[Arr[_, _]] extends Compose[Op[Arr, *, *]] { f.compose(g) } -private[data] trait OpDecidable[Arr[_, _], R] extends Decidable[Op[Arr, R, ?]] with OpContravariantMonoidal[Arr, R] { +private[data] trait OpDecidable[Arr[_, _], R] extends Decidable[Op[Arr, R, *]] with OpContravariantMonoidal[Arr, R] { implicit def Arr: ArrowChoice[Arr] implicit def M: Monoid[R] @@ -100,7 +100,7 @@ private[data] trait OpDecidable[Arr[_, _], R] extends Decidable[Op[Arr, R, ?]] w private[data] trait OpContravariantMonoidal[Arr[_, _], R] extends OpContravariant[Arr, R] - with ContravariantMonoidal[Op[Arr, R, ?]] { + with ContravariantMonoidal[Op[Arr, R, *]] { implicit def Arr: Arrow[Arr] implicit def M: Monoid[R] @@ -111,7 +111,7 @@ private[data] trait OpContravariantMonoidal[Arr[_, _], R] Op(Arr.compose(Arr.lift((M.combine _).tupled), Arr.split(fa.run, fb.run))) } -private[data] trait OpContravariant[Arr[_, _], R] extends Contravariant[Op[Arr, R, ?]] { +private[data] trait OpContravariant[Arr[_, _], R] extends Contravariant[Op[Arr, R, *]] { implicit def Arr: Arrow[Arr] def contramap[A, B](fa: Op[Arr, R, A])(f: B => A): Op[Arr, R, B] = diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index e66f997620..ffa517613b 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -582,7 +582,7 @@ sealed abstract private[data] class OptionTInstances1 extends OptionTInstances2 implicit def catsDataContravariantMonoidalForOptionT[F[_]](implicit F0: ContravariantMonoidal[F] - ): ContravariantMonoidal[OptionT[F, ?]] = + ): ContravariantMonoidal[OptionT[F, *]] = new OptionTContravariantMonoidal[F] { implicit val F = F0 } } diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index e66b895d71..3fb7e2341f 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -522,7 +522,7 @@ sealed abstract private[data] class WriterTInstances7 extends WriterTInstances8 implicit def catsDataDecidableForWriterT[F[_], L](implicit F: Decidable[F] - ): Decidable[WriterT[F, L, ?]] = + ): Decidable[WriterT[F, L, *]] = new WriterTDecidable[F, L] { implicit val F0: Decidable[F] = F } diff --git a/tests/shared/src/test/scala/cats/tests/ContravariantSuite.scala b/tests/shared/src/test/scala/cats/tests/ContravariantSuite.scala index 1c34f6abc5..5e70ac69c7 100644 --- a/tests/shared/src/test/scala/cats/tests/ContravariantSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/ContravariantSuite.scala @@ -28,6 +28,7 @@ import cats.laws.discipline.arbitrary._ import cats.laws.discipline.{DecidableTests, MiniInt} import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal} import cats.laws.discipline.eq._ +import cats.tests.Predicate import org.scalacheck.{Arbitrary, Cogen} import org.scalacheck.Prop._ diff --git a/tests/shared/src/test/scala/cats/tests/EqSuite.scala b/tests/shared/src/test/scala/cats/tests/EqSuite.scala index 7e8d24beb2..0ce04a5bd3 100644 --- a/tests/shared/src/test/scala/cats/tests/EqSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/EqSuite.scala @@ -21,10 +21,10 @@ package cats.tests -import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal, Invariant, Semigroupal} +import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal, Decidable, Invariant, Semigroupal} import cats.kernel.Eq import cats.kernel.laws.discipline.SerializableTests -import cats.laws.discipline.{Decideable, MiniInt} +import cats.laws.discipline.{DecidableTests, MiniInt} import cats.laws.discipline.arbitrary._ import cats.laws.discipline.eq._ @@ -35,7 +35,7 @@ class EqSuite extends CatsSuite { ContravariantSemigroupal[Eq] Decidable[Eq] - checkAll("Eq", Decidable[Eq].decidable[MiniInt, Boolean, Boolean]) + checkAll("Eq", DecidableTests[Eq].decidable[MiniInt, Boolean, Boolean]) checkAll("Decidable[Eq]", SerializableTests.serializable(Decidable[Eq])) } diff --git a/tests/shared/src/test/scala/cats/tests/EquivSuite.scala b/tests/shared/src/test/scala/cats/tests/EquivSuite.scala index c46f10c530..e0ad16d1c3 100644 --- a/tests/shared/src/test/scala/cats/tests/EquivSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/EquivSuite.scala @@ -40,6 +40,6 @@ class EquivSuite extends CatsSuite { checkAll("ContravariantMonoidal[Equiv]", ContravariantMonoidalTests[Equiv].contravariantMonoidal[MiniInt, Boolean, Boolean] ) - checkAll("Decidable[Equiv]", DecidableTests.decidable[MiniInt, Boolean, Boolean]) + checkAll("Decidable[Equiv]", DecidableTests[Equiv].decidable[MiniInt, Boolean, Boolean]) checkAll("Decidable[Equiv]", SerializableTests.serializable(Decidable[Equiv])) } diff --git a/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala b/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala index 1c9e160867..680d69df6a 100644 --- a/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala @@ -23,12 +23,11 @@ package cats.tests import cats._ import cats.arrow._ -import cats.data._ -import cats.implicits._ +import cats.data.{Const, EitherT, Kleisli, Reader, ReaderT} import cats.kernel.laws.discipline.{MonoidTests, SemigroupTests} -import cats.laws.discipline.SemigroupalTests.Isomorphisms import cats.laws.discipline.arbitrary._ import cats.laws.discipline.eq._ +import cats.laws.discipline._ import cats.laws.discipline.SemigroupalTests.Isomorphisms import cats.laws.discipline.{DeferTests, MonoidKTests, SemigroupKTests} import cats.syntax.all._ @@ -133,7 +132,7 @@ class KleisliSuite extends CatsSuite { DecidableTests[Kleisli[Predicate, MiniInt, *]].decidable[MiniInt, MiniInt, MiniInt] ) checkAll( - "Decidable[Kleisli[Option, Int, ?]]", + "Decidable[Kleisli[Option, Int, *]]", SerializableTests.serializable[Decidable[Kleisli[Predicate, MiniInt, *]]]( Decidable[Kleisli[Predicate, MiniInt, *]] ) @@ -143,11 +142,11 @@ class KleisliSuite extends CatsSuite { { implicit val catsDataContravariantMonoidalForKleisli = Kleisli.catsDataContravariantMonoidalForKleisli[Const[String, *], Int] - checkAll("Kleisli[Const[String, ?], MiniInt, ?]", + checkAll("Kleisli[Const[String, *], MiniInt, *]", ContravariantMonoidalTests[Kleisli[Const[String, *], MiniInt, *]].contravariantMonoidal[Int, Int, Int] ) - checkAll("ContravariantMonoidal[Kleisli[Option, Int, ?]]", - SerializableTests.serializable(ContravariantMonoidal[Kleisli[Const[String, ?], Int, ?]]) + checkAll("ContravariantMonoidal[Kleisli[Option, Int, *]]", + SerializableTests.serializable(ContravariantMonoidal[Kleisli[Const[String, *], Int, *]]) ) } diff --git a/tests/shared/src/test/scala/cats/tests/OrderSuite.scala b/tests/shared/src/test/scala/cats/tests/OrderSuite.scala index 6027ddb5fd..4b3ed3711e 100644 --- a/tests/shared/src/test/scala/cats/tests/OrderSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/OrderSuite.scala @@ -21,7 +21,7 @@ package cats.tests -import cats.{Contravariant, ContravariantMonoidal, Decidable, Invariant} +import cats.{Contravariant, ContravariantMonoidal, Invariant} import cats.kernel.{Order, PartialOrder} import cats.kernel.laws.discipline.{OrderTests, SerializableTests} import cats.laws.discipline.{ContravariantMonoidalTests, MiniInt} @@ -36,7 +36,6 @@ class OrderSuite extends CatsSuite { Invariant[Order] Contravariant[Order] ContravariantMonoidal[Order] - Decidable[Order] } checkAll("Int", OrderTests[Int].order) @@ -47,9 +46,6 @@ class OrderSuite extends CatsSuite { checkAll("Order", ContravariantMonoidalTests[Order].contravariantMonoidal[MiniInt, Boolean, Boolean]) checkAll("ContravariantMonoidal[Order]", SerializableTests.serializable(ContravariantMonoidal[Order])) - checkAll("Order", Decidable[Order].decidable[MiniInt, Boolean, Boolean]) - checkAll("Decidable[Order]", SerializableTests.serializable(Decidable[Order])) - test("order ops syntax") { forAll { (i: Ord, j: Ord) => assert((i.compare(j)) === (Order.compare(i, j))) diff --git a/tests/shared/src/test/scala/cats/tests/OrderingSuite.scala b/tests/shared/src/test/scala/cats/tests/OrderingSuite.scala index 0403e7bb58..1eb478c4ac 100644 --- a/tests/shared/src/test/scala/cats/tests/OrderingSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/OrderingSuite.scala @@ -21,7 +21,7 @@ package cats.tests -import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal, Decidable, Invariant, Semigroupal} +import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal, Invariant, Semigroupal} import cats.laws.discipline.arbitrary._ import cats.laws.discipline._ import cats.laws.discipline.eq._ @@ -33,13 +33,11 @@ class OrderingSuite extends CatsSuite { Semigroupal[Ordering] ContravariantSemigroupal[Ordering] ContravariantMonoidal[Ordering] - Decidable[Ordering] checkAll("Contravariant[Ordering]", ContravariantTests[Ordering].contravariant[MiniInt, Int, Boolean]) checkAll("Semigroupal[Ordering]", SemigroupalTests[Ordering].semigroupal[MiniInt, Boolean, Boolean]) checkAll("ContravariantMonoidal[Ordering]", ContravariantMonoidalTests[Ordering].contravariantMonoidal[MiniInt, Boolean, Boolean] ) - checkAll(Decidable[Ordering].decidable[MiniInt, Boolean, Boolean]) checkAll("ContravariantMonoidal[Ordering]", SerializableTests.serializable(ContravariantMonoidal[Ordering])) } diff --git a/tests/src/test/scala/cats/tests/Predicate.scala b/tests/shared/src/test/scala/cats/tests/Predicate.scala similarity index 100% rename from tests/src/test/scala/cats/tests/Predicate.scala rename to tests/shared/src/test/scala/cats/tests/Predicate.scala From 45966c3b56b3bb3bd00119868424e93520f3072b Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Sun, 26 Jun 2022 13:39:56 -1000 Subject: [PATCH 44/87] Formatting --- core/src/main/scala/cats/Decidable.scala | 1 + core/src/main/scala/cats/Invariant.scala | 1 - core/src/main/scala/cats/data/OptionT.scala | 4 ++-- .../main/scala/cats/instances/function.scala | 4 ++-- .../main/scala/cats/laws/DecidableLaws.scala | 17 ++++++++--------- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/core/src/main/scala/cats/Decidable.scala b/core/src/main/scala/cats/Decidable.scala index 94ff6b2dd5..81d4f653b7 100644 --- a/core/src/main/scala/cats/Decidable.scala +++ b/core/src/main/scala/cats/Decidable.scala @@ -29,6 +29,7 @@ trait Decidable[F[_]] extends ContravariantMonoidal[F] { } object Decidable { + /** * Summon an instance of [[Decidable]] for `F`. */ diff --git a/core/src/main/scala/cats/Invariant.scala b/core/src/main/scala/cats/Invariant.scala index d3dd3f187c..53f63fc920 100644 --- a/core/src/main/scala/cats/Invariant.scala +++ b/core/src/main/scala/cats/Invariant.scala @@ -191,7 +191,6 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn implicit def catsInvariantForFractional: Invariant[Fractional] = cats.instances.invariant.catsInvariantForFractional - implicit def catsDecidableForEquiv: Decidable[Equiv] = cats.instances.equiv.catsDecidableForEquiv implicit def catsDecidableForEq: Decidable[Eq] = diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index ffa517613b..413d033d4e 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -670,10 +670,10 @@ private trait OptionTContravariantMonoidal[F[_]] extends ContravariantMonoidal[O override def product[A, B](fa: OptionT[F, A], fb: OptionT[F, B]): OptionT[F, (A, B)] = OptionT( - F.contramap(F.product(fa.value, fb.value))({ + F.contramap(F.product(fa.value, fb.value)) { case Some((x, y)) => (Some(x), Some(y)) case None => (None, None) - }) + } ) } diff --git a/core/src/main/scala/cats/instances/function.scala b/core/src/main/scala/cats/instances/function.scala index 2a344baabc..9adee313e7 100644 --- a/core/src/main/scala/cats/instances/function.scala +++ b/core/src/main/scala/cats/instances/function.scala @@ -85,8 +85,8 @@ private[instances] trait FunctionInstancesBinCompat0 { def unit: Unit => Boolean = Function.const(false) def contramap[A, B](fa: A => Boolean)(f: B => A): B => Boolean = fa.compose(f) - def product[A, B](fa: A => Boolean, fb: B => Boolean): ((A, B)) => Boolean = { - case (a, b) => fa(a) || fb(b) + def product[A, B](fa: A => Boolean, fb: B => Boolean): ((A, B)) => Boolean = { case (a, b) => + fa(a) || fb(b) } def sum[A, B](fa: A => Boolean, fb: B => Boolean): Either[A, B] => Boolean = either => either.fold(fa, fb) diff --git a/laws/src/main/scala/cats/laws/DecidableLaws.scala b/laws/src/main/scala/cats/laws/DecidableLaws.scala index fd47776209..448332cb8a 100644 --- a/laws/src/main/scala/cats/laws/DecidableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecidableLaws.scala @@ -15,13 +15,12 @@ trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { fb: F[B], fc: F[C] ): IsEq[F[Either[Either[A, B], C]]] = - F.contramap[Either[A, Either[B, C]], Either[Either[A, B], C]](F.sum(fa, F.sum(fb, fc)))( - { - case Left(Left(x)) => Left(x) - case Left(Right(x)) => Right(Left(x)) - case Right(x) => Right(Right(x)) - } - ) <-> F.sum(F.sum(fa, fb), fc) + F.contramap[Either[A, Either[B, C]], Either[Either[A, B], C]](F.sum(fa, F.sum(fb, fc))) { + case Left(Left(x)) => Left(x) + case Left(Right(x)) => Right(Left(x)) + case Right(x) => Right(Right(x)) + } + <-> F.sum(F.sum(fa, fb), fc) def decidableRightDistributivity[A, B, C](fa: F[A], fb: F[B], f: C => A, g: C => B): IsEq[F[Either[C, C]]] = F.contramap(F.sum(fa, fb))((eit: Either[C, C]) => @@ -33,10 +32,10 @@ trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { def decidableRightDistributivitySum[A, B, C](fa: F[A], fb: F[B], fc: F[C]): IsEq[F[(A, Either[B, C])]] = F.product(fa, F.sum(fb, fc)) <-> - F.contramap(F.sum(F.product(fa, fb), F.product(fa, fc)))({ + F.contramap(F.sum(F.product(fa, fb), F.product(fa, fc))) { case (a, Left(b)) => Left((a, b)) case (a, Right(c)) => Right((a, c)) - }) + } } object DecidableLaws { From 91962c44ecd6c6cc170444a763f094d7ed6a6bcf Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Sun, 26 Jun 2022 15:34:06 -1000 Subject: [PATCH 45/87] Heaaders for rights --- core/src/main/scala/cats/Decidable.scala | 21 +++++++++++++++++++ .../main/scala/cats/laws/DecidableLaws.scala | 21 +++++++++++++++++++ .../cats/laws/discipline/DecidableTests.scala | 21 +++++++++++++++++++ .../src/test/scala/cats/tests/Predicate.scala | 21 +++++++++++++++++++ 4 files changed, 84 insertions(+) diff --git a/core/src/main/scala/cats/Decidable.scala b/core/src/main/scala/cats/Decidable.scala index 81d4f653b7..372776e31c 100644 --- a/core/src/main/scala/cats/Decidable.scala +++ b/core/src/main/scala/cats/Decidable.scala @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 Typelevel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + package cats import cats.data.INothing diff --git a/laws/src/main/scala/cats/laws/DecidableLaws.scala b/laws/src/main/scala/cats/laws/DecidableLaws.scala index 448332cb8a..5153bed0e7 100644 --- a/laws/src/main/scala/cats/laws/DecidableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecidableLaws.scala @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 Typelevel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + package cats package laws diff --git a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala index 074647d32f..0bdd4b79d6 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 Typelevel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + package cats package laws package discipline diff --git a/tests/shared/src/test/scala/cats/tests/Predicate.scala b/tests/shared/src/test/scala/cats/tests/Predicate.scala index 54ad66e21e..e11242d5b6 100644 --- a/tests/shared/src/test/scala/cats/tests/Predicate.scala +++ b/tests/shared/src/test/scala/cats/tests/Predicate.scala @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 Typelevel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + package cats.tests import cats.Decidable From 72289b14752e3f8dfb16bbfb71b81149cafba193 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 27 Jun 2022 10:01:38 -1000 Subject: [PATCH 46/87] Clean docs and suchlike --- CONTRIBUTING.md | 2 +- docs/typeclasses/{decideable.md => decidable.md} | 13 +++---------- docs/typeclasses/directory.conf | 3 ++- laws/src/main/scala/cats/laws/DecidableLaws.scala | 3 +-- 4 files changed, 7 insertions(+), 14 deletions(-) rename docs/typeclasses/{decideable.md => decidable.md} (92%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 01c2b75824..8254f49d86 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -105,7 +105,7 @@ To build Cats you should have * `console`: launch a REPL * `test`: run the tests * `unidoc`: generate the documentation - * `fmt`: run formatting of the code + * `scalafmt`: run formatting of the code * `validate`: run tests, style-checker, and doc generation #### Scala and Scala.js diff --git a/docs/typeclasses/decideable.md b/docs/typeclasses/decidable.md similarity index 92% rename from docs/typeclasses/decideable.md rename to docs/typeclasses/decidable.md index fe87ec1f90..7eaac40d53 100644 --- a/docs/typeclasses/decideable.md +++ b/docs/typeclasses/decidable.md @@ -1,10 +1,3 @@ ---- -layout: docs -title: "Decidable" -section: "typeclasses" -source: "core/src/main/scala/cats/Decidable.scala" -scaladoc: "#cats.Decidable" ---- # Decidable The `Decidable` type class is an extension of [`ContravariantMonoidal`](contravariantmonoidal.html) that allows the @@ -12,7 +5,7 @@ definition of a `sum` function, allowing us to make choices in consuming our inp It is the contravariant analogue of the [`Alternative`](alternative.html) type class. -```tut:silent +```scala mdoc:silent import cats.ContravariantMonoidal import cats.data.INothing @@ -38,7 +31,7 @@ The classic example of a `Decidable` is that of predicates `A => Boolean`, leani We can write the instance as: -```tut:silent +```scala mdoc:silent implicit val decideableForPredicates = new Decidable[* => Boolean] { def zero[A]: INothing => Boolean = _ => true def unit: Unit => Boolean = Function.const(false) @@ -56,7 +49,7 @@ implicit val decideableForPredicates = new Decidable[* => Boolean] { This can be used to combine predicates over both sum types and product types. -```tut +```scala mdoc def isEven(i: Int): Boolean = i % 2 == 0 def isDivisibleByThree(l: Long): Boolean = l % 3 == 0 diff --git a/docs/typeclasses/directory.conf b/docs/typeclasses/directory.conf index 08270eb62b..56eb8dc5db 100644 --- a/docs/typeclasses/directory.conf +++ b/docs/typeclasses/directory.conf @@ -12,6 +12,7 @@ laika.navigationOrder = [ comonad.md contravariant.md contravariantmonoidal.md + decidable.md eq.md foldable.md functor.md @@ -28,4 +29,4 @@ laika.navigationOrder = [ semigroupk.md show.md traverse.md -] \ No newline at end of file +] diff --git a/laws/src/main/scala/cats/laws/DecidableLaws.scala b/laws/src/main/scala/cats/laws/DecidableLaws.scala index 5153bed0e7..42b3ad35cd 100644 --- a/laws/src/main/scala/cats/laws/DecidableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecidableLaws.scala @@ -40,8 +40,7 @@ trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { case Left(Left(x)) => Left(x) case Left(Right(x)) => Right(Left(x)) case Right(x) => Right(Right(x)) - } - <-> F.sum(F.sum(fa, fb), fc) + } <-> F.sum(F.sum(fa, fb), fc) def decidableRightDistributivity[A, B, C](fa: F[A], fb: F[B], f: C => A, g: C => B): IsEq[F[Either[C, C]]] = F.contramap(F.sum(fa, fb))((eit: Either[C, C]) => From 87fe2367eecd9c4bb277db942c47a3ec7bf2c259 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 27 Jun 2022 10:17:35 -1000 Subject: [PATCH 47/87] No implicitNotFound --- core/src/main/scala/cats/Decidable.scala | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/src/main/scala/cats/Decidable.scala b/core/src/main/scala/cats/Decidable.scala index 372776e31c..bb7a0850c0 100644 --- a/core/src/main/scala/cats/Decidable.scala +++ b/core/src/main/scala/cats/Decidable.scala @@ -23,8 +23,6 @@ package cats import cats.data.INothing -import scala.annotation.implicitNotFound - /** * [[Decidable]] functors are functors that supply * a `decide` operation allowing choices to be made. @@ -37,7 +35,6 @@ import scala.annotation.implicitNotFound * Based on ekmett's contravariant library: * https://hackage.haskell.org/package/contravariant-1.4/docs/Data-Functor-Contravariant-Divisible.html#g:2 */ -@implicitNotFound("Could not find an instance of Decidable for ${F}") trait Decidable[F[_]] extends ContravariantMonoidal[F] { def sum[A, B](fa: F[A], fb: F[B]): F[Either[A, B]] From 3d96d066291a10b3c4e96f57271f926778dc3e9d Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 27 Jun 2022 10:18:59 -1000 Subject: [PATCH 48/87] Accidental newline --- build.sbt | 1 - 1 file changed, 1 deletion(-) diff --git a/build.sbt b/build.sbt index 37bf484a3e..5194816a3f 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,3 @@ - ThisBuild / tlBaseVersion := "2.9" val scalaCheckVersion = "1.16.0" From 8ab26f19110516520d776f51788778a6e1fc1506 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 27 Jun 2022 10:52:31 -1000 Subject: [PATCH 49/87] s/INothing/Nothing/g --- CONTRIBUTING.md | 2 +- core/src/main/scala/cats/Composed.scala | 4 +--- core/src/main/scala/cats/Decidable.scala | 6 ++---- core/src/main/scala/cats/data/IdT.scala | 2 +- core/src/main/scala/cats/data/Kleisli.scala | 4 ++-- core/src/main/scala/cats/data/Nested.scala | 2 +- core/src/main/scala/cats/data/Op.scala | 6 ++++-- core/src/main/scala/cats/data/Tuple2K.scala | 2 +- core/src/main/scala/cats/data/WriterT.scala | 2 +- core/src/main/scala/cats/data/package.scala | 5 +---- core/src/main/scala/cats/instances/eq.scala | 18 +++++------------- .../src/main/scala/cats/instances/equiv.scala | 19 ++++++------------- .../main/scala/cats/instances/function.scala | 4 ++-- .../scala/cats/tests/ContravariantSuite.scala | 3 --- .../src/test/scala/cats/tests/Predicate.scala | 3 +-- 15 files changed, 29 insertions(+), 53 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8254f49d86..7b130ace6d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -105,7 +105,7 @@ To build Cats you should have * `console`: launch a REPL * `test`: run the tests * `unidoc`: generate the documentation - * `scalafmt`: run formatting of the code + * `scalafmtAll`: run formatting of the code * `validate`: run tests, style-checker, and doc generation #### Scala and Scala.js diff --git a/core/src/main/scala/cats/Composed.scala b/core/src/main/scala/cats/Composed.scala index 7de3a5f2a4..844e20ba3a 100644 --- a/core/src/main/scala/cats/Composed.scala +++ b/core/src/main/scala/cats/Composed.scala @@ -21,8 +21,6 @@ package cats -import cats.data.INothing - private[cats] trait ComposedDistributive[F[_], G[_]] extends Distributive[λ[α => F[G[α]]]] with ComposedFunctor[F, G] { outer => def F: Distributive[F] @@ -187,7 +185,7 @@ private[cats] trait ComposedApplicativeDecidable[F[_], G[_]] def sum[A, B](fa: F[G[A]], fb: F[G[B]]): F[G[Either[A, B]]] = F.map(F.product(fa, fb))(Function.tupled(G.sum)) - override def zero[A]: F[G[INothing]] = F.pure(G.zero) + override def zero: F[G[Nothing]] = F.pure(G.zero) } private[cats] trait ComposedApplicativeContravariantMonoidal[F[_], G[_]] diff --git a/core/src/main/scala/cats/Decidable.scala b/core/src/main/scala/cats/Decidable.scala index bb7a0850c0..c2cf7ff16a 100644 --- a/core/src/main/scala/cats/Decidable.scala +++ b/core/src/main/scala/cats/Decidable.scala @@ -21,8 +21,6 @@ package cats -import cats.data.INothing - /** * [[Decidable]] functors are functors that supply * a `decide` operation allowing choices to be made. @@ -42,8 +40,8 @@ trait Decidable[F[_]] extends ContravariantMonoidal[F] { contramap(sum(fa, fb))(f) def chosen[B, C](fb: F[B], fc: F[C]): F[Either[B, C]] = sum(fb, fc) - def lose[A](f: A => INothing): F[A] = contramap[INothing, A](zero)(f) - def zero[A]: F[INothing] + def lose[A](f: A => Nothing): F[A] = contramap[Nothing, A](zero)(f) + def zero: F[Nothing] } object Decidable { diff --git a/core/src/main/scala/cats/data/IdT.scala b/core/src/main/scala/cats/data/IdT.scala index c9bae7ab58..d980980102 100644 --- a/core/src/main/scala/cats/data/IdT.scala +++ b/core/src/main/scala/cats/data/IdT.scala @@ -100,7 +100,7 @@ sealed private[data] trait IdTDecidable[F[_]] extends Decidable[IdT[F, *]] with override def sum[A, B](fa: IdT[F, A], fb: IdT[F, B]): IdT[F, Either[A, B]] = IdT(F0.sum(fa.value, fb.value)) - override def zero[A]: IdT[F, INothing] = IdT(F0.zero) + override def zero: IdT[F, Nothing] = IdT[F, Nothing](F0.zero) } sealed private[data] trait IdTContravariantMonoidal[F[_]] extends ContravariantMonoidal[IdT[F, *]] { diff --git a/core/src/main/scala/cats/data/Kleisli.scala b/core/src/main/scala/cats/data/Kleisli.scala index 67d7b7e80b..3539021c62 100644 --- a/core/src/main/scala/cats/data/Kleisli.scala +++ b/core/src/main/scala/cats/data/Kleisli.scala @@ -625,8 +625,8 @@ sealed private[data] trait KleisliDecidable[F[_], D] def sum[A, B](fa: Kleisli[F, D, A], fb: Kleisli[F, D, B]): Kleisli[F, D, Either[A, B]] = Kleisli(d => F.sum(fa.run(d), fb.run(d))) - override def zero[A]: ReaderT[F, D, INothing] = - Kleisli(_ => F.zero) + override def zero: ReaderT[F, D, Nothing] = + Kleisli[F, D, Nothing](_ => F.zero) } sealed private[data] trait KleisliContravariantMonoidal[F[_], D] extends ContravariantMonoidal[Kleisli[F, D, *]] { diff --git a/core/src/main/scala/cats/data/Nested.scala b/core/src/main/scala/cats/data/Nested.scala index 1182ada896..6dee062879 100644 --- a/core/src/main/scala/cats/data/Nested.scala +++ b/core/src/main/scala/cats/data/Nested.scala @@ -408,7 +408,7 @@ private[data] trait NestedDecidable[F[_], G[_]] def sum[A, B](fa: Nested[F, G, A], fb: Nested[F, G, B]): Nested[F, G, Either[A, B]] = Nested(FG.sum(fa.value, fb.value)) - def zero[A]: Nested[F, G, INothing] = Nested(FG.zero) + def zero: Nested[F, G, Nothing] = Nested[F, G, Nothing](FG.zero) } private[data] trait NestedContravariantMonoidal[F[_], G[_]] extends ContravariantMonoidal[Nested[F, G, *]] { diff --git a/core/src/main/scala/cats/data/Op.scala b/core/src/main/scala/cats/data/Op.scala index 7f0a6e8ab6..13807eaf0a 100644 --- a/core/src/main/scala/cats/data/Op.scala +++ b/core/src/main/scala/cats/data/Op.scala @@ -94,8 +94,10 @@ private[data] trait OpDecidable[Arr[_, _], R] extends Decidable[Op[Arr, R, *]] w def sum[A, B](fa: Op[Arr, R, A], fb: Op[Arr, R, B]): Op[Arr, R, Either[A, B]] = Op(Arr.choice(fa.run, fb.run)) - override def zero[A]: Op[Arr, R, INothing] = - Op(Arr.lift(INothing.absurd)) + override def zero: Op[Arr, R, Nothing] = + Op[Arr, R, Nothing]( + Arr.lift[Nothing, R](_ => throw new Exception("Materialized a value of type `Nothing`, this is a bug!")) + ) } private[data] trait OpContravariantMonoidal[Arr[_, _], R] diff --git a/core/src/main/scala/cats/data/Tuple2K.scala b/core/src/main/scala/cats/data/Tuple2K.scala index 72565cb3b8..60c4c297f4 100644 --- a/core/src/main/scala/cats/data/Tuple2K.scala +++ b/core/src/main/scala/cats/data/Tuple2K.scala @@ -318,7 +318,7 @@ sealed private[data] trait Tuple2KDecidable[F[_], G[_]] def sum[A, B](fa: Tuple2K[F, G, A], fb: Tuple2K[F, G, B]): Tuple2K[F, G, Either[A, B]] = Tuple2K(F.sum(fa.first, fb.first), G.sum(fa.second, fb.second)) - def zero[A]: Tuple2K[F, G, INothing] = Tuple2K(F.zero, G.zero) + def zero: Tuple2K[F, G, Nothing] = Tuple2K[F, G, Nothing](F.zero, G.zero) } sealed private[data] trait Tuple2KContravariantMonoidal[F[_], G[_]] diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index 3fb7e2341f..9b60268510 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -773,7 +773,7 @@ sealed private[data] trait WriterTDecidable[F[_], L] ) ) - override def zero[A]: WriterT[F, L, INothing] = WriterT(F0.contramap(F0.zero)(_._2)) + override def zero: WriterT[F, L, Nothing] = WriterT[F, L, Nothing](F0.contramap[Nothing, (L, Nothing)](F0.zero)(_._2)) } sealed private[data] trait WriterTContravariantMonoidal[F[_], L] extends ContravariantMonoidal[WriterT[F, L, *]] { diff --git a/core/src/main/scala/cats/data/package.scala b/core/src/main/scala/cats/data/package.scala index 60aec95cf2..9c514dddc1 100644 --- a/core/src/main/scala/cats/data/package.scala +++ b/core/src/main/scala/cats/data/package.scala @@ -143,8 +143,5 @@ package object data extends ScalaVersionSpecificPackage { } - type INothing <: Nothing - object INothing { - def absurd[A](n: INothing): A = throw new Exception("Somehow instantiated a value of INothing, this is a bug.") - } + def absurd[A](n: Nothing): A = throw new Exception("Somehow instantiated a value of INothing, this is a bug.") } diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index 4608fd95f1..8bc2b9ec2f 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -22,10 +22,6 @@ package cats package instances -import cats.data.INothing -import cats.instances.either._ -import cats.syntax.apply._ - trait EqInstances extends kernel.instances.EqInstances with EqInstances0 { implicit def catsDecidableForEq: Decidable[Eq] = new Decidable[Eq] { @@ -50,17 +46,13 @@ trait EqInstances extends kernel.instances.EqInstances with EqInstances0 { } def sum[A, B](fa: Eq[A], fb: Eq[B]): Eq[Either[A, B]] = - Eq.instance { (left, right) => - if (left.isRight) - if (right.isRight) - (left, right).mapN(fb.eqv).toOption.get - else false - else if (right.isLeft) - (left.swap, right.swap).mapN(fa.eqv).toOption.get - else false + Eq.instance { + case (Left(a1), Left(a2)) => fa.eqv(a1, a2) + case (Right(b1), Right(b2)) => fb.eqv(b1, b2) + case _ => false } - override def zero[A]: Eq[INothing] = Eq.allEqual[INothing] + override def zero: Eq[Nothing] = Eq.allEqual[Nothing] } } diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index 022540e20d..23e97fcf81 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -22,10 +22,6 @@ package cats package instances -import cats.data.INothing -import cats.instances.either._ -import cats.syntax.apply._ - trait EquivInstances extends EquivInstances0 { implicit def catsDecidableForEquiv: Decidable[Equiv] = new Decidable[Equiv] { @@ -58,17 +54,14 @@ trait EquivInstances extends EquivInstances0 { def sum[A, B](fa: Equiv[A], fb: Equiv[B]): Equiv[Either[A, B]] = new Equiv[Either[A, B]] { - def equiv(x: Either[A, B], y: Either[A, B]): Boolean = - if (x.isRight) - if (y.isRight) - (x, y).mapN(fb.equiv).toOption.get - else false - else if (y.isLeft) - (x.swap, y.swap).mapN(fa.equiv).toOption.get - else false + def equiv(x: Either[A, B], y: Either[A, B]): Boolean = (x, y) match { + case (Left(a1), Left(a2)) => fa.equiv(a1, a2) + case (Right(b1), Right(b2)) => fb.equiv(b1, b2) + case _ => false + } } - override def zero[A]: Equiv[INothing] = Equiv.by(_ => ()) + override def zero: Equiv[Nothing] = Equiv.by[Nothing, Unit](_ => ()) } } diff --git a/core/src/main/scala/cats/instances/function.scala b/core/src/main/scala/cats/instances/function.scala index 9adee313e7..ebc4ae261b 100644 --- a/core/src/main/scala/cats/instances/function.scala +++ b/core/src/main/scala/cats/instances/function.scala @@ -23,7 +23,7 @@ package cats package instances import cats.arrow.{ArrowChoice, Category, CommutativeArrow} -import cats.data.{AndThen, INothing} +import cats.data.AndThen import annotation.tailrec @@ -90,7 +90,7 @@ private[instances] trait FunctionInstancesBinCompat0 { } def sum[A, B](fa: A => Boolean, fb: B => Boolean): Either[A, B] => Boolean = either => either.fold(fa, fb) - def zero[A]: INothing => Boolean = _ => true + def zero: Nothing => Boolean = _ => true } } diff --git a/tests/shared/src/test/scala/cats/tests/ContravariantSuite.scala b/tests/shared/src/test/scala/cats/tests/ContravariantSuite.scala index 5e70ac69c7..9640a59415 100644 --- a/tests/shared/src/test/scala/cats/tests/ContravariantSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/ContravariantSuite.scala @@ -27,9 +27,6 @@ import cats.kernel.{Monoid, Semigroup} import cats.laws.discipline.arbitrary._ import cats.laws.discipline.{DecidableTests, MiniInt} import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal} -import cats.laws.discipline.eq._ -import cats.tests.Predicate -import org.scalacheck.{Arbitrary, Cogen} import org.scalacheck.Prop._ class ContravariantSuite extends CatsSuite { diff --git a/tests/shared/src/test/scala/cats/tests/Predicate.scala b/tests/shared/src/test/scala/cats/tests/Predicate.scala index e11242d5b6..63fdafd206 100644 --- a/tests/shared/src/test/scala/cats/tests/Predicate.scala +++ b/tests/shared/src/test/scala/cats/tests/Predicate.scala @@ -22,7 +22,6 @@ package cats.tests import cats.Decidable -import cats.data.INothing import cats.kernel.Eq import cats.laws.discipline.eq._ import cats.laws.discipline.ExhaustiveCheck @@ -39,7 +38,7 @@ object Predicate { Predicate(x => fa.run(f(x))) def sum[A, B](fa: Predicate[A], fb: Predicate[B]): Predicate[Either[A, B]] = Predicate(_.fold(fa.run, fb.run)) - def zero[A]: Predicate[INothing] = Predicate(_ => true) + def zero: Predicate[Nothing] = Predicate[Nothing](_ => true) } implicit def eqPredicate[A: ExhaustiveCheck]: Eq[Predicate[A]] = From 9edb1e4d28de9ef242e56bbcf4f124c91c0c421c Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 28 Jun 2022 09:50:37 -1000 Subject: [PATCH 50/87] Make some things vals, re-organize methods --- core/src/main/scala/cats/Decidable.scala | 2 +- core/src/main/scala/cats/data/Kleisli.scala | 2 +- core/src/main/scala/cats/data/package.scala | 2 -- core/src/main/scala/cats/instances/eq.scala | 2 +- core/src/main/scala/cats/instances/equiv.scala | 2 +- core/src/main/scala/cats/instances/function.scala | 2 +- 6 files changed, 5 insertions(+), 7 deletions(-) diff --git a/core/src/main/scala/cats/Decidable.scala b/core/src/main/scala/cats/Decidable.scala index c2cf7ff16a..82cccc0d75 100644 --- a/core/src/main/scala/cats/Decidable.scala +++ b/core/src/main/scala/cats/Decidable.scala @@ -35,13 +35,13 @@ package cats */ trait Decidable[F[_]] extends ContravariantMonoidal[F] { def sum[A, B](fa: F[A], fb: F[B]): F[Either[A, B]] + def zero: F[Nothing] def decide[A, B, C](fa: F[A], fb: F[B])(f: C => Either[A, B]): F[C] = contramap(sum(fa, fb))(f) def chosen[B, C](fb: F[B], fc: F[C]): F[Either[B, C]] = sum(fb, fc) def lose[A](f: A => Nothing): F[A] = contramap[Nothing, A](zero)(f) - def zero: F[Nothing] } object Decidable { diff --git a/core/src/main/scala/cats/data/Kleisli.scala b/core/src/main/scala/cats/data/Kleisli.scala index 3539021c62..96a1eac6d8 100644 --- a/core/src/main/scala/cats/data/Kleisli.scala +++ b/core/src/main/scala/cats/data/Kleisli.scala @@ -625,7 +625,7 @@ sealed private[data] trait KleisliDecidable[F[_], D] def sum[A, B](fa: Kleisli[F, D, A], fb: Kleisli[F, D, B]): Kleisli[F, D, Either[A, B]] = Kleisli(d => F.sum(fa.run(d), fb.run(d))) - override def zero: ReaderT[F, D, Nothing] = + override val zero: ReaderT[F, D, Nothing] = Kleisli[F, D, Nothing](_ => F.zero) } diff --git a/core/src/main/scala/cats/data/package.scala b/core/src/main/scala/cats/data/package.scala index 9c514dddc1..4ac5961361 100644 --- a/core/src/main/scala/cats/data/package.scala +++ b/core/src/main/scala/cats/data/package.scala @@ -142,6 +142,4 @@ package object data extends ScalaVersionSpecificPackage { RepresentableStoreT.pure[W, Function1[S, *], S, A](x) } - - def absurd[A](n: Nothing): A = throw new Exception("Somehow instantiated a value of INothing, this is a bug.") } diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index 8bc2b9ec2f..4f606dc9c0 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -52,7 +52,7 @@ trait EqInstances extends kernel.instances.EqInstances with EqInstances0 { case _ => false } - override def zero: Eq[Nothing] = Eq.allEqual[Nothing] + override val zero: Eq[Nothing] = Eq.allEqual[Nothing] } } diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index 23e97fcf81..2b92083d59 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -61,7 +61,7 @@ trait EquivInstances extends EquivInstances0 { } } - override def zero: Equiv[Nothing] = Equiv.by[Nothing, Unit](_ => ()) + override val zero: Equiv[Nothing] = Equiv.by[Nothing, Unit](_ => ()) } } diff --git a/core/src/main/scala/cats/instances/function.scala b/core/src/main/scala/cats/instances/function.scala index ebc4ae261b..e73f5d6a3a 100644 --- a/core/src/main/scala/cats/instances/function.scala +++ b/core/src/main/scala/cats/instances/function.scala @@ -90,7 +90,7 @@ private[instances] trait FunctionInstancesBinCompat0 { } def sum[A, B](fa: A => Boolean, fb: B => Boolean): Either[A, B] => Boolean = either => either.fold(fa, fb) - def zero: Nothing => Boolean = _ => true + val zero: Nothing => Boolean = _ => true } } From ffe0459700955af15adbcd70c0eb59cd174effca Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 28 Jun 2022 09:53:32 -1000 Subject: [PATCH 51/87] Avoid binary incompat --- core/src/main/scala/cats/Invariant.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/scala/cats/Invariant.scala b/core/src/main/scala/cats/Invariant.scala index 53f63fc920..067b0ceaeb 100644 --- a/core/src/main/scala/cats/Invariant.scala +++ b/core/src/main/scala/cats/Invariant.scala @@ -176,6 +176,10 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn cats.instances.ordering.catsContravariantMonoidalForOrdering implicit def catsContravariantMonoidalForPartialOrdering: ContravariantMonoidal[PartialOrdering] = cats.instances.partialOrdering.catsContravariantMonoidalForPartialOrdering + def catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = + cats.instances.eq.catsContravariantMonoidalForEq + def catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = + cats.instances.equiv.catsContravariantMonoidalForEquiv implicit def catsContravariantForHash: Contravariant[Hash] = cats.instances.all.catsContravariantForHash implicit def catsInvariantMonoidalForSemigroup: InvariantMonoidal[Semigroup] = From 8bcaa2ea20133b0b774c53fe56bf8d0abac4f74d Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 28 Jun 2022 09:55:14 -1000 Subject: [PATCH 52/87] Make alias final --- core/src/main/scala/cats/Decidable.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/Decidable.scala b/core/src/main/scala/cats/Decidable.scala index 82cccc0d75..9a111b99a1 100644 --- a/core/src/main/scala/cats/Decidable.scala +++ b/core/src/main/scala/cats/Decidable.scala @@ -40,7 +40,7 @@ trait Decidable[F[_]] extends ContravariantMonoidal[F] { def decide[A, B, C](fa: F[A], fb: F[B])(f: C => Either[A, B]): F[C] = contramap(sum(fa, fb))(f) - def chosen[B, C](fb: F[B], fc: F[C]): F[Either[B, C]] = sum(fb, fc) + final def chosen[B, C](fb: F[B], fc: F[C]): F[Either[B, C]] = sum(fb, fc) def lose[A](f: A => Nothing): F[A] = contramap[Nothing, A](zero)(f) } From da8224a65123a62772ea4fb8081af385b2fb4787 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 28 Jun 2022 09:57:00 -1000 Subject: [PATCH 53/87] Another val --- core/src/main/scala/cats/instances/function.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/instances/function.scala b/core/src/main/scala/cats/instances/function.scala index e73f5d6a3a..014436a675 100644 --- a/core/src/main/scala/cats/instances/function.scala +++ b/core/src/main/scala/cats/instances/function.scala @@ -82,7 +82,7 @@ private[instances] trait FunctionInstancesBinCompat0 { implicit def catsStdDecidableForPredicate: Decidable[* => Boolean] = new Decidable[* => Boolean] { - def unit: Unit => Boolean = Function.const(false) + val unit: Unit => Boolean = Function.const(false) def contramap[A, B](fa: A => Boolean)(f: B => A): B => Boolean = fa.compose(f) def product[A, B](fa: A => Boolean, fb: B => Boolean): ((A, B)) => Boolean = { case (a, b) => From b051a4d627b23e10022bec638c6a5fd5534b4b28 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Wed, 29 Jun 2022 09:56:35 -1000 Subject: [PATCH 54/87] More vals, some docs cleaning --- core/src/main/scala/cats/Composed.scala | 2 +- core/src/main/scala/cats/data/IdT.scala | 2 +- core/src/main/scala/cats/data/Nested.scala | 2 +- core/src/main/scala/cats/data/Op.scala | 4 ++-- core/src/main/scala/cats/data/Tuple2K.scala | 2 +- core/src/main/scala/cats/data/WriterT.scala | 2 +- core/src/main/scala/cats/instances/either.scala | 2 +- core/src/main/scala/cats/instances/eq.scala | 2 +- core/src/main/scala/cats/instances/function.scala | 2 +- docs/typeclasses/decidable.md | 6 ++---- 10 files changed, 12 insertions(+), 14 deletions(-) diff --git a/core/src/main/scala/cats/Composed.scala b/core/src/main/scala/cats/Composed.scala index 844e20ba3a..dc144a478c 100644 --- a/core/src/main/scala/cats/Composed.scala +++ b/core/src/main/scala/cats/Composed.scala @@ -185,7 +185,7 @@ private[cats] trait ComposedApplicativeDecidable[F[_], G[_]] def sum[A, B](fa: F[G[A]], fb: F[G[B]]): F[G[Either[A, B]]] = F.map(F.product(fa, fb))(Function.tupled(G.sum)) - override def zero: F[G[Nothing]] = F.pure(G.zero) + override val zero: F[G[Nothing]] = F.pure(G.zero) } private[cats] trait ComposedApplicativeContravariantMonoidal[F[_], G[_]] diff --git a/core/src/main/scala/cats/data/IdT.scala b/core/src/main/scala/cats/data/IdT.scala index d980980102..e992b44be2 100644 --- a/core/src/main/scala/cats/data/IdT.scala +++ b/core/src/main/scala/cats/data/IdT.scala @@ -100,7 +100,7 @@ sealed private[data] trait IdTDecidable[F[_]] extends Decidable[IdT[F, *]] with override def sum[A, B](fa: IdT[F, A], fb: IdT[F, B]): IdT[F, Either[A, B]] = IdT(F0.sum(fa.value, fb.value)) - override def zero: IdT[F, Nothing] = IdT[F, Nothing](F0.zero) + override val zero: IdT[F, Nothing] = IdT[F, Nothing](F0.zero) } sealed private[data] trait IdTContravariantMonoidal[F[_]] extends ContravariantMonoidal[IdT[F, *]] { diff --git a/core/src/main/scala/cats/data/Nested.scala b/core/src/main/scala/cats/data/Nested.scala index 6dee062879..5ffe79404a 100644 --- a/core/src/main/scala/cats/data/Nested.scala +++ b/core/src/main/scala/cats/data/Nested.scala @@ -408,7 +408,7 @@ private[data] trait NestedDecidable[F[_], G[_]] def sum[A, B](fa: Nested[F, G, A], fb: Nested[F, G, B]): Nested[F, G, Either[A, B]] = Nested(FG.sum(fa.value, fb.value)) - def zero: Nested[F, G, Nothing] = Nested[F, G, Nothing](FG.zero) + val zero: Nested[F, G, Nothing] = Nested[F, G, Nothing](FG.zero) } private[data] trait NestedContravariantMonoidal[F[_], G[_]] extends ContravariantMonoidal[Nested[F, G, *]] { diff --git a/core/src/main/scala/cats/data/Op.scala b/core/src/main/scala/cats/data/Op.scala index 13807eaf0a..02737b549f 100644 --- a/core/src/main/scala/cats/data/Op.scala +++ b/core/src/main/scala/cats/data/Op.scala @@ -94,9 +94,9 @@ private[data] trait OpDecidable[Arr[_, _], R] extends Decidable[Op[Arr, R, *]] w def sum[A, B](fa: Op[Arr, R, A], fb: Op[Arr, R, B]): Op[Arr, R, Either[A, B]] = Op(Arr.choice(fa.run, fb.run)) - override def zero: Op[Arr, R, Nothing] = + override val zero: Op[Arr, R, Nothing] = Op[Arr, R, Nothing]( - Arr.lift[Nothing, R](_ => throw new Exception("Materialized a value of type `Nothing`, this is a bug!")) + Arr.lift[Nothing, R]((n: Nothing) => n: R) ) } diff --git a/core/src/main/scala/cats/data/Tuple2K.scala b/core/src/main/scala/cats/data/Tuple2K.scala index 60c4c297f4..436e8b5df8 100644 --- a/core/src/main/scala/cats/data/Tuple2K.scala +++ b/core/src/main/scala/cats/data/Tuple2K.scala @@ -318,7 +318,7 @@ sealed private[data] trait Tuple2KDecidable[F[_], G[_]] def sum[A, B](fa: Tuple2K[F, G, A], fb: Tuple2K[F, G, B]): Tuple2K[F, G, Either[A, B]] = Tuple2K(F.sum(fa.first, fb.first), G.sum(fa.second, fb.second)) - def zero: Tuple2K[F, G, Nothing] = Tuple2K[F, G, Nothing](F.zero, G.zero) + val zero: Tuple2K[F, G, Nothing] = Tuple2K[F, G, Nothing](F.zero, G.zero) } sealed private[data] trait Tuple2KContravariantMonoidal[F[_], G[_]] diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index 9b60268510..c36ad02008 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -773,7 +773,7 @@ sealed private[data] trait WriterTDecidable[F[_], L] ) ) - override def zero: WriterT[F, L, Nothing] = WriterT[F, L, Nothing](F0.contramap[Nothing, (L, Nothing)](F0.zero)(_._2)) + override val zero: WriterT[F, L, Nothing] = WriterT[F, L, Nothing](F0.contramap[Nothing, (L, Nothing)](F0.zero)(_._2)) } sealed private[data] trait WriterTContravariantMonoidal[F[_], L] extends ContravariantMonoidal[WriterT[F, L, *]] { diff --git a/core/src/main/scala/cats/instances/either.scala b/core/src/main/scala/cats/instances/either.scala index d61f83ea30..14c4bb15c1 100644 --- a/core/src/main/scala/cats/instances/either.scala +++ b/core/src/main/scala/cats/instances/either.scala @@ -59,7 +59,7 @@ trait EitherInstances extends cats.kernel.instances.EitherInstances { implicit def catsStdInstancesForEither[A] : MonadError[Either[A, *], A] with Traverse[Either[A, *]] with Align[Either[A, *]] = new MonadError[Either[A, *], A] with Traverse[Either[A, *]] with Align[Either[A, *]] { - override def unit: Either[A, Unit] = Either.unit + override val unit: Either[A, Unit] = Either.unit def pure[B](b: B): Either[A, B] = Right(b) diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index 4f606dc9c0..a72e4434f1 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -30,7 +30,7 @@ trait EqInstances extends kernel.instances.EqInstances with EqInstances0 { * Defaults to the trivial equivalence relation * contracting the type to a point */ - def unit: Eq[Unit] = Eq.allEqual + val unit: Eq[Unit] = Eq.allEqual /** * Derive an `Eq` for `B` given an `Eq[A]` and a function `B => A`. diff --git a/core/src/main/scala/cats/instances/function.scala b/core/src/main/scala/cats/instances/function.scala index 014436a675..91f945dbe5 100644 --- a/core/src/main/scala/cats/instances/function.scala +++ b/core/src/main/scala/cats/instances/function.scala @@ -90,7 +90,7 @@ private[instances] trait FunctionInstancesBinCompat0 { } def sum[A, B](fa: A => Boolean, fb: B => Boolean): Either[A, B] => Boolean = either => either.fold(fa, fb) - val zero: Nothing => Boolean = _ => true + val zero: Nothing => Boolean = Function.const(true) } } diff --git a/docs/typeclasses/decidable.md b/docs/typeclasses/decidable.md index 7eaac40d53..b764f4359b 100644 --- a/docs/typeclasses/decidable.md +++ b/docs/typeclasses/decidable.md @@ -7,15 +7,13 @@ It is the contravariant analogue of the [`Alternative`](alternative.html) type c ```scala mdoc:silent import cats.ContravariantMonoidal -import cats.data.INothing trait Decidable[F[_]] extends ContravariantMonoidal[F] { def sum[A, B](fa: F[A], fb: F[B]): F[Either[A, B]] + def zero[A]: F[Nothing] def decide[A, B, C](fa: F[A], fb: F[B])(f: C => Either[A, B]): F[C] = contramap(sum(fa, fb))(f) - - def zero[A]: F[INothing] } object Decidable { def apply[F[_]](implicit dec: Decidable[F]): Decidable[F] = @@ -33,7 +31,7 @@ We can write the instance as: ```scala mdoc:silent implicit val decideableForPredicates = new Decidable[* => Boolean] { - def zero[A]: INothing => Boolean = _ => true + def zero[A]: Nothing => Boolean = _ => true def unit: Unit => Boolean = Function.const(false) def contramap[A, B](fa: A => Boolean)(f: B => A): B => Boolean = fa.compose(f) From c787ae8a088ce6bde6f970d9656464ac299a4320 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Wed, 29 Jun 2022 09:58:39 -1000 Subject: [PATCH 55/87] Remove Haskell style name aliases --- core/src/main/scala/cats/ContravariantMonoidal.scala | 1 - core/src/main/scala/cats/Decidable.scala | 1 - 2 files changed, 2 deletions(-) diff --git a/core/src/main/scala/cats/ContravariantMonoidal.scala b/core/src/main/scala/cats/ContravariantMonoidal.scala index 1cddc54b21..205655002c 100644 --- a/core/src/main/scala/cats/ContravariantMonoidal.scala +++ b/core/src/main/scala/cats/ContravariantMonoidal.scala @@ -38,7 +38,6 @@ trait ContravariantMonoidal[F[_]] extends ContravariantSemigroupal[F] with Invar * the diagonal */ def trivial[A]: F[A] = contramap(unit)(_ => ()) - def conquer[A]: F[A] = trivial[A] } object ContravariantMonoidal extends SemigroupalArityFunctions { def monoid[F[_], A](implicit f: ContravariantMonoidal[F]): Monoid[F[A]] = diff --git a/core/src/main/scala/cats/Decidable.scala b/core/src/main/scala/cats/Decidable.scala index 9a111b99a1..0efe18ca81 100644 --- a/core/src/main/scala/cats/Decidable.scala +++ b/core/src/main/scala/cats/Decidable.scala @@ -40,7 +40,6 @@ trait Decidable[F[_]] extends ContravariantMonoidal[F] { def decide[A, B, C](fa: F[A], fb: F[B])(f: C => Either[A, B]): F[C] = contramap(sum(fa, fb))(f) - final def chosen[B, C](fb: F[B], fc: F[C]): F[Either[B, C]] = sum(fb, fc) def lose[A](f: A => Nothing): F[A] = contramap[Nothing, A](zero)(f) } From 13570c71219326ef1399e31e587edec16a936500 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Wed, 29 Jun 2022 10:01:35 -1000 Subject: [PATCH 56/87] Another val --- core/src/main/scala/cats/data/Op.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/Op.scala b/core/src/main/scala/cats/data/Op.scala index 02737b549f..184b7ae6ec 100644 --- a/core/src/main/scala/cats/data/Op.scala +++ b/core/src/main/scala/cats/data/Op.scala @@ -106,7 +106,7 @@ private[data] trait OpContravariantMonoidal[Arr[_, _], R] implicit def Arr: Arrow[Arr] implicit def M: Monoid[R] - def unit: Op[Arr, R, Unit] = + val unit: Op[Arr, R, Unit] = Op(Arr.lift(Function.const(M.empty))) def product[A, B](fa: Op[Arr, R, A], fb: Op[Arr, R, B]): Op[Arr, R, (A, B)] = From 7cc84b76f7ff5f07311633be19ff0f0e161d7884 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Wed, 29 Jun 2022 10:02:53 -1000 Subject: [PATCH 57/87] Equiv `val` --- core/src/main/scala/cats/instances/equiv.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index 2b92083d59..923b40b741 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -73,7 +73,7 @@ private[instances] trait EquivInstances0 { * Defaults to trivially contracting the type * to a point */ - def unit: Equiv[Unit] = + val unit: Equiv[Unit] = new Equiv[Unit] { def equiv(x: Unit, y: Unit): Boolean = true } From fef5ff09c49c641e4b595cd958db47d2e9b78a6a Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Wed, 29 Jun 2022 10:04:55 -1000 Subject: [PATCH 58/87] Correct for managed code no longer managed --- core/src/main/scala/cats/Decidable.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/scala/cats/Decidable.scala b/core/src/main/scala/cats/Decidable.scala index 0efe18ca81..17662386c1 100644 --- a/core/src/main/scala/cats/Decidable.scala +++ b/core/src/main/scala/cats/Decidable.scala @@ -67,7 +67,6 @@ object Decidable { val typeClassInstance: TypeClassType def sum[B](fb: F[B]): F[Either[A, B]] = typeClassInstance.sum[A, B](self, fb) def decide[B, C](fb: F[B])(f: C => Either[A, B]): F[C] = typeClassInstance.decide[A, B, C](self, fb)(f) - def chosen[B](fc: F[B]): F[Either[A, B]] = typeClassInstance.chosen[A, B](self, fc) } trait AllOps[F[_], A] extends Ops[F, A] with ContravariantMonoidal.AllOps[F, A] { type TypeClassType <: Decidable[F] From 011c8ebab454a36c4892e64a8a10c2643ede8d20 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Wed, 29 Jun 2022 10:07:28 -1000 Subject: [PATCH 59/87] Use simpler expression in Composed --- core/src/main/scala/cats/Composed.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/Composed.scala b/core/src/main/scala/cats/Composed.scala index dc144a478c..73a5dc3733 100644 --- a/core/src/main/scala/cats/Composed.scala +++ b/core/src/main/scala/cats/Composed.scala @@ -183,7 +183,7 @@ private[cats] trait ComposedApplicativeDecidable[F[_], G[_]] def G: Decidable[G] def sum[A, B](fa: F[G[A]], fb: F[G[B]]): F[G[Either[A, B]]] = - F.map(F.product(fa, fb))(Function.tupled(G.sum)) + F.map2(fa, fb)(G.sum) override val zero: F[G[Nothing]] = F.pure(G.zero) } From 7066dbde86548893c722aefea851b76662b2b1ea Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Thu, 30 Jun 2022 11:16:25 -1000 Subject: [PATCH 60/87] Adjust initialization, clean a couple tests --- core/src/main/scala/cats/Composed.scala | 2 +- core/src/main/scala/cats/data/IdT.scala | 2 +- core/src/main/scala/cats/data/Nested.scala | 2 +- laws/src/main/scala/cats/laws/discipline/DecidableTests.scala | 4 ++-- tests/shared/src/test/scala/cats/tests/EqSuite.scala | 1 + 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/cats/Composed.scala b/core/src/main/scala/cats/Composed.scala index 73a5dc3733..227e83f851 100644 --- a/core/src/main/scala/cats/Composed.scala +++ b/core/src/main/scala/cats/Composed.scala @@ -185,7 +185,7 @@ private[cats] trait ComposedApplicativeDecidable[F[_], G[_]] def sum[A, B](fa: F[G[A]], fb: F[G[B]]): F[G[Either[A, B]]] = F.map2(fa, fb)(G.sum) - override val zero: F[G[Nothing]] = F.pure(G.zero) + override lazy val zero: F[G[Nothing]] = F.pure(G.zero) } private[cats] trait ComposedApplicativeContravariantMonoidal[F[_], G[_]] diff --git a/core/src/main/scala/cats/data/IdT.scala b/core/src/main/scala/cats/data/IdT.scala index e992b44be2..1196a918f7 100644 --- a/core/src/main/scala/cats/data/IdT.scala +++ b/core/src/main/scala/cats/data/IdT.scala @@ -100,7 +100,7 @@ sealed private[data] trait IdTDecidable[F[_]] extends Decidable[IdT[F, *]] with override def sum[A, B](fa: IdT[F, A], fb: IdT[F, B]): IdT[F, Either[A, B]] = IdT(F0.sum(fa.value, fb.value)) - override val zero: IdT[F, Nothing] = IdT[F, Nothing](F0.zero) + override lazy val zero: IdT[F, Nothing] = IdT[F, Nothing](F0.zero) } sealed private[data] trait IdTContravariantMonoidal[F[_]] extends ContravariantMonoidal[IdT[F, *]] { diff --git a/core/src/main/scala/cats/data/Nested.scala b/core/src/main/scala/cats/data/Nested.scala index 5ffe79404a..193c128da3 100644 --- a/core/src/main/scala/cats/data/Nested.scala +++ b/core/src/main/scala/cats/data/Nested.scala @@ -408,7 +408,7 @@ private[data] trait NestedDecidable[F[_], G[_]] def sum[A, B](fa: Nested[F, G, A], fb: Nested[F, G, B]): Nested[F, G, Either[A, B]] = Nested(FG.sum(fa.value, fb.value)) - val zero: Nested[F, G, Nothing] = Nested[F, G, Nothing](FG.zero) + lazy val zero: Nested[F, G, Nothing] = Nested[F, G, Nothing](FG.zero) } private[data] trait NestedContravariantMonoidal[F[_], G[_]] extends ContravariantMonoidal[Nested[F, G, *]] { diff --git a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala index 0bdd4b79d6..16eb2da22a 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala @@ -50,7 +50,7 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { val parents = Seq(contravariantMonoidal[A, B, C]) val bases = Seq.empty val props = Seq( - "decideable left identity" -> + "decidable left identity" -> forAll(laws.decidableDecideLeftIdentity[A] _), "decidable right identity" -> forAll(laws.decidableDecideRightIdentity[A] _), @@ -58,7 +58,7 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { forAll(laws.decidableSumAssociativity[A, B, C] _), "decidable right distributivity" -> forAll(laws.decidableRightDistributivity[A, B, C] _), - "dedicable right sum distributivituy" -> + "decidable right sum distributivity" -> forAll(laws.decidableRightDistributivitySum[A, B, C] _) ) } diff --git a/tests/shared/src/test/scala/cats/tests/EqSuite.scala b/tests/shared/src/test/scala/cats/tests/EqSuite.scala index 0ce04a5bd3..bec95cebb1 100644 --- a/tests/shared/src/test/scala/cats/tests/EqSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/EqSuite.scala @@ -33,6 +33,7 @@ class EqSuite extends CatsSuite { Contravariant[Eq] Semigroupal[Eq] ContravariantSemigroupal[Eq] + ContravariantMonoidal[Eq] Decidable[Eq] checkAll("Eq", DecidableTests[Eq].decidable[MiniInt, Boolean, Boolean]) From cb51073708f40414a68842326545957a8f84af15 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Fri, 1 Jul 2022 10:32:45 -1000 Subject: [PATCH 61/87] Fix inter-doc link --- docs/typeclasses/decidable.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/typeclasses/decidable.md b/docs/typeclasses/decidable.md index b764f4359b..ae2ccea68f 100644 --- a/docs/typeclasses/decidable.md +++ b/docs/typeclasses/decidable.md @@ -1,9 +1,9 @@ # Decidable -The `Decidable` type class is an extension of [`ContravariantMonoidal`](contravariantmonoidal.html) that allows the +The `Decidable` type class is an extension of [`ContravariantMonoidal`](contravariantmonoidal.md) that allows the definition of a `sum` function, allowing us to make choices in consuming our input. -It is the contravariant analogue of the [`Alternative`](alternative.html) type class. +It is the contravariant analogue of the [`Alternative`](alternative.md) type class. ```scala mdoc:silent import cats.ContravariantMonoidal From 92dfde73902ae443babccf28b3e4f27338480e4e Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Fri, 1 Jul 2022 10:53:14 -1000 Subject: [PATCH 62/87] Fix JS linking in tests --- .../shared/src/test/scala/cats/tests/FunctionSuite.scala | 3 ++- tests/shared/src/test/scala/cats/tests/KleisliSuite.scala | 3 ++- tests/shared/src/test/scala/cats/tests/OpSuite.scala | 8 +++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/shared/src/test/scala/cats/tests/FunctionSuite.scala b/tests/shared/src/test/scala/cats/tests/FunctionSuite.scala index 55a26cc210..8a29ee6cc2 100644 --- a/tests/shared/src/test/scala/cats/tests/FunctionSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/FunctionSuite.scala @@ -184,7 +184,8 @@ class FunctionSuite extends CatsSuite { ) // Isos for Decidable - implicit val isoCodomainBoolean = SemigroupalTests.Isomorphisms.invariant[Function1[*, Boolean]] + implicit val isoCodomainBoolean: Isomorphisms[Function1[*, Boolean]] = + SemigroupalTests.Isomorphisms.invariant[Function1[*, Boolean]] checkAll("Function1[?, Boolean]", DecidableTests[Function1[*, Boolean]].decidable[MiniInt, MiniInt, MiniInt]) checkAll("Decidable[? => Boolean]", SerializableTests.serializable(Decidable[Function1[*, Boolean]])) diff --git a/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala b/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala index 680d69df6a..9e877e7ad0 100644 --- a/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala @@ -140,7 +140,8 @@ class KleisliSuite extends CatsSuite { } { - implicit val catsDataContravariantMonoidalForKleisli = + implicit val catsDataContravariantMonoidalForKleisliLocal + : ContravariantMonoidal[Kleisli[Const[String, *], Int, *]] = Kleisli.catsDataContravariantMonoidalForKleisli[Const[String, *], Int] checkAll("Kleisli[Const[String, *], MiniInt, *]", ContravariantMonoidalTests[Kleisli[Const[String, *], MiniInt, *]].contravariantMonoidal[Int, Int, Int] diff --git a/tests/shared/src/test/scala/cats/tests/OpSuite.scala b/tests/shared/src/test/scala/cats/tests/OpSuite.scala index 342147d7a2..59bf6d26c3 100644 --- a/tests/shared/src/test/scala/cats/tests/OpSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/OpSuite.scala @@ -44,13 +44,14 @@ class OpSuite extends CatsSuite { } { - implicit val catsDataDecidableForOp = Op.catsDataDecidableForOp[Function1, Int] + implicit val catsDataDecidableForOp: Decidable[Op[Function1, Int, *]] = Op.catsDataDecidableForOp[Function1, Int] checkAll("Op[Function1, Monoid, ?]", DecidableTests[Op[Function1, Int, *]].decidable[MiniInt, MiniInt, MiniInt]) checkAll("Decidable[Op[Function1, Monoid, ?]]", SerializableTests.serializable(Decidable[Op[Function1, Int, *]])) } { - implicit val catsDataContravariantMonoidalForOp = Op.catsDataContravariantMonoidalForOp[Function1, Int] + implicit val catsDataContravariantMonoidalForOp: ContravariantMonoidal[Op[Function1, Int, *]] = + Op.catsDataContravariantMonoidalForOp[Function1, Int] checkAll("Op[Function1, Monoid, ?]", ContravariantMonoidalTests[Op[Function1, Int, *]].contravariantMonoidal[MiniInt, MiniInt, MiniInt] ) @@ -61,7 +62,8 @@ class OpSuite extends CatsSuite { } { - implicit val catsDataContravariantForOp = Op.catsDataContravariantMonoidalForOp[Function1, Unit] + implicit val catsDataContravariantForOp: ContravariantMonoidal[Op[Function1, Unit, *]] = + Op.catsDataContravariantMonoidalForOp[Function1, Unit] checkAll("Op[Function1, Unit, ?]", ContravariantTests[Op[Function1, Unit, *]].contravariant[MiniInt, MiniInt, MiniInt] ) From 28447524715242d7e1f395cb72b1ade5bcb1a0a5 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Fri, 1 Jul 2022 11:23:06 -1000 Subject: [PATCH 63/87] Add a couple MIMA exceptions --- mima.sbt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mima.sbt b/mima.sbt index 67d4cf5c9e..a8874e984b 100644 --- a/mima.sbt +++ b/mima.sbt @@ -145,6 +145,10 @@ ThisBuild / mimaBinaryIssueFilters ++= { exclude[ReversedAbstractMethodProblem]("cats.free.ContravariantCoyoneda.k"), exclude[DirectAbstractMethodProblem]("cats.free.Coyoneda.k"), exclude[ReversedAbstractMethodProblem]("cats.free.Coyoneda.k") + ) ++ // https://typelevel/cats/pull/2607 + Seq( + exclude[DirectMissingMethodProblem]("cats.instances.EqInstances.$init$"), + exclude[DirectMissingMethodProblem]("cats.instances.EquivInstances.$init$") ) } From 0e3ebe8fd8dce981dd0a1732b3f35141bf2db76c Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Fri, 1 Jul 2022 15:59:51 -1000 Subject: [PATCH 64/87] Actually fix bincompat, not exclude --- core/src/main/scala/cats/instances/eq.scala | 5 ++++- core/src/main/scala/cats/instances/equiv.scala | 5 ++++- mima.sbt | 4 ---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index a72e4434f1..b6d3d2ab18 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -54,10 +54,13 @@ trait EqInstances extends kernel.instances.EqInstances with EqInstances0 { override val zero: Eq[Nothing] = Eq.allEqual[Nothing] } + + val catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = + catsContravariantMonoidalForEqForBinCompat } private[instances] trait EqInstances0 { - implicit def catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = + implicit def catsContravariantMonoidalForEqForBinCompat: ContravariantMonoidal[Eq] = new ContravariantMonoidal[Eq] { /** diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index 923b40b741..48d00ff956 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -63,10 +63,13 @@ trait EquivInstances extends EquivInstances0 { override val zero: Equiv[Nothing] = Equiv.by[Nothing, Unit](_ => ()) } + + val catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = + catsContravariantMonoidalForEquivForBinCompat } private[instances] trait EquivInstances0 { - implicit def catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = + implicit def catsContravariantMonoidalForEquivForBinCompat: ContravariantMonoidal[Equiv] = new ContravariantMonoidal[Equiv] { /** diff --git a/mima.sbt b/mima.sbt index a8874e984b..67d4cf5c9e 100644 --- a/mima.sbt +++ b/mima.sbt @@ -145,10 +145,6 @@ ThisBuild / mimaBinaryIssueFilters ++= { exclude[ReversedAbstractMethodProblem]("cats.free.ContravariantCoyoneda.k"), exclude[DirectAbstractMethodProblem]("cats.free.Coyoneda.k"), exclude[ReversedAbstractMethodProblem]("cats.free.Coyoneda.k") - ) ++ // https://typelevel/cats/pull/2607 - Seq( - exclude[DirectMissingMethodProblem]("cats.instances.EqInstances.$init$"), - exclude[DirectMissingMethodProblem]("cats.instances.EquivInstances.$init$") ) } From 3a0b2c424fccb2576769c3fc8f24eb3c42bcfddb Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Fri, 1 Jul 2022 16:02:44 -1000 Subject: [PATCH 65/87] Fix the formatting --- core/src/main/scala/cats/instances/eq.scala | 2 +- core/src/main/scala/cats/instances/equiv.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index b6d3d2ab18..31dde7ef92 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -55,7 +55,7 @@ trait EqInstances extends kernel.instances.EqInstances with EqInstances0 { override val zero: Eq[Nothing] = Eq.allEqual[Nothing] } - val catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = + val catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = catsContravariantMonoidalForEqForBinCompat } diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index 48d00ff956..d66924fd6d 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -64,8 +64,8 @@ trait EquivInstances extends EquivInstances0 { override val zero: Equiv[Nothing] = Equiv.by[Nothing, Unit](_ => ()) } - val catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = - catsContravariantMonoidalForEquivForBinCompat + val catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = + catsContravariantMonoidalForEquivForBinCompat } private[instances] trait EquivInstances0 { From 7730debb3209aa4a28db92f01dd7e8ff943d33c8 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Fri, 1 Jul 2022 16:42:34 -1000 Subject: [PATCH 66/87] Update CONTRIBUTING with `prePR` --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7b130ace6d..906bbf7301 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -106,7 +106,7 @@ To build Cats you should have * `test`: run the tests * `unidoc`: generate the documentation * `scalafmtAll`: run formatting of the code - * `validate`: run tests, style-checker, and doc generation + * `prePR`: run tests, style-checker, and doc generation #### Scala and Scala.js From 68c27f28fd7253549a79b043aa9942d23c917bfc Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 5 Jul 2022 18:12:46 -0700 Subject: [PATCH 67/87] Commit suggested doc comment change Co-authored-by: Arman Bilge --- core/src/main/scala/cats/Decidable.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/Decidable.scala b/core/src/main/scala/cats/Decidable.scala index 17662386c1..7ecfaf21d7 100644 --- a/core/src/main/scala/cats/Decidable.scala +++ b/core/src/main/scala/cats/Decidable.scala @@ -28,7 +28,7 @@ package cats * This is comparable to [[Alternative]] in the * covariant case. * - * Must obey laws in cats.laws.DecidableLaws. + * Must obey laws in `cats.laws.DecidableLaws`. * * Based on ekmett's contravariant library: * https://hackage.haskell.org/package/contravariant-1.4/docs/Data-Functor-Contravariant-Divisible.html#g:2 From 4814ed521091b5989c3b71762231f2335a43f3b6 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 5 Jul 2022 18:13:12 -0700 Subject: [PATCH 68/87] Commit link to original source change Co-authored-by: Arman Bilge --- core/src/main/scala/cats/Decidable.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/Decidable.scala b/core/src/main/scala/cats/Decidable.scala index 7ecfaf21d7..bdd3670c66 100644 --- a/core/src/main/scala/cats/Decidable.scala +++ b/core/src/main/scala/cats/Decidable.scala @@ -31,7 +31,7 @@ package cats * Must obey laws in `cats.laws.DecidableLaws`. * * Based on ekmett's contravariant library: - * https://hackage.haskell.org/package/contravariant-1.4/docs/Data-Functor-Contravariant-Divisible.html#g:2 + * [[https://hackage.haskell.org/package/contravariant-1.4/docs/Data-Functor-Contravariant-Divisible.html#g:2]] */ trait Decidable[F[_]] extends ContravariantMonoidal[F] { def sum[A, B](fa: F[A], fb: F[B]): F[Either[A, B]] From 3daa7e1942914104c17ae6033e42c7acc975fc26 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 5 Jul 2022 18:23:26 -0700 Subject: [PATCH 69/87] Clean and modernize syntax --- core/src/main/scala/cats/Decidable.scala | 13 ------------- core/src/main/scala/cats/syntax/all.scala | 1 + .../src/test/scala/cats/tests/SyntaxSuite.scala | 10 +++++++++- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/core/src/main/scala/cats/Decidable.scala b/core/src/main/scala/cats/Decidable.scala index bdd3670c66..14c5bb4b29 100644 --- a/core/src/main/scala/cats/Decidable.scala +++ b/core/src/main/scala/cats/Decidable.scala @@ -50,17 +50,6 @@ object Decidable { */ @inline def apply[F[_]](implicit instance: Decidable[F]): Decidable[F] = instance - @deprecated("Use cats.syntax object imports", "2.2.0") - object ops { - implicit def toAllDecidableOps[F[_], A](target: F[A])(implicit tc: Decidable[F]): AllOps[F, A] { - type TypeClassType = Decidable[F] - } = - new AllOps[F, A] { - type TypeClassType = Decidable[F] - val self: F[A] = target - val typeClassInstance: TypeClassType = tc - } - } trait Ops[F[_], A] extends Serializable { type TypeClassType <: Decidable[F] def self: F[A] @@ -81,6 +70,4 @@ object Decidable { val typeClassInstance: TypeClassType = tc } } - @deprecated("Use cats.syntax object imports", "2.2.0") - object nonInheritedOps extends ToDecidableOps } diff --git a/core/src/main/scala/cats/syntax/all.scala b/core/src/main/scala/cats/syntax/all.scala index 60d6d2b150..16643b4362 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -50,6 +50,7 @@ trait AllSyntax with ComonadSyntax with ComposeSyntax with ContravariantSyntax + with DecidableSyntax with DistributiveSyntax with ContravariantMonoidalSyntax with ContravariantSemigroupalSyntax diff --git a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala index 432e4f5596..9f58725ae3 100644 --- a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala @@ -115,12 +115,20 @@ object SyntaxSuite { val fb: F[B] = fa.imap(f)(g) } - def testInvariantFunctor[F[_]: Contravariant, A, B]: Unit = { + def testContravariantFunctor[F[_]: Contravariant, A, B]: Unit = { val fa = mock[F[A]] val f = mock[B => A] val fb: F[B] = fa.contramap(f) } + def testDecidableFunctor[F[_]: Decidable, A, B, C]: Unit = { + val fa = mock[F[A]] + val fb = mock[F[B]] + val f = mock[C => Either[A, B]] + val fc = fa.sum(fb) + val fd = fa.decide(fb)(f) + } + def testFoldable[F[_]: Foldable, G[_]: Applicative: MonoidK, A: Monoid, B, Z]: Unit = { val fa = mock[F[A]] val b = mock[B] From 587f274f68766af275034ee2747f5de31fcd55c0 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 5 Jul 2022 18:27:18 -0700 Subject: [PATCH 70/87] Fix syntax modernization and add deprecations on old instances --- core/src/main/scala/cats/Invariant.scala | 3 ++ .../main/scala/cats/syntax/decidable.scala | 37 +++++++++++++++++++ .../test/scala/cats/tests/SyntaxSuite.scala | 2 +- 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 core/src/main/scala/cats/syntax/decidable.scala diff --git a/core/src/main/scala/cats/Invariant.scala b/core/src/main/scala/cats/Invariant.scala index 067b0ceaeb..30fb3c46f3 100644 --- a/core/src/main/scala/cats/Invariant.scala +++ b/core/src/main/scala/cats/Invariant.scala @@ -176,8 +176,11 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn cats.instances.ordering.catsContravariantMonoidalForOrdering implicit def catsContravariantMonoidalForPartialOrdering: ContravariantMonoidal[PartialOrdering] = cats.instances.partialOrdering.catsContravariantMonoidalForPartialOrdering + + @deprecated("Prefer cats.instances.eq.catsDecidableForEq, which supersedes this instance", "2.9.0") def catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = cats.instances.eq.catsContravariantMonoidalForEq + @deprecated("Prefer cats.instances.eq.catsDecidableForEquiv, which supersedes this instance", "2.9.0") def catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = cats.instances.equiv.catsContravariantMonoidalForEquiv implicit def catsContravariantForHash: Contravariant[Hash] = diff --git a/core/src/main/scala/cats/syntax/decidable.scala b/core/src/main/scala/cats/syntax/decidable.scala new file mode 100644 index 0000000000..7e69564a63 --- /dev/null +++ b/core/src/main/scala/cats/syntax/decidable.scala @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015 Typelevel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package cats +package syntax + +import cats.Decidable + +trait DecidableSyntax extends ContravariantMonoidalSyntax { + implicit final def catsSyntaxDecidable[F[_], A]( + fa: F[A] + )(implicit F: Decidable[F]): Decidable.Ops[F, A] = + new Decidable.Ops[F, A] { + type TypeClassType = Decidable[F] + + val self = fa + val typeClassInstance = F + } +} diff --git a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala index 9f58725ae3..570cc08749 100644 --- a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala @@ -124,7 +124,7 @@ object SyntaxSuite { def testDecidableFunctor[F[_]: Decidable, A, B, C]: Unit = { val fa = mock[F[A]] val fb = mock[F[B]] - val f = mock[C => Either[A, B]] + val f = mock[C => Either[A, B]] val fc = fa.sum(fb) val fd = fa.decide(fb)(f) } From 73033a1bdac1733033d31052f5fbc3dbf252871d Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 5 Jul 2022 18:38:05 -0700 Subject: [PATCH 71/87] s/ReaderT/Kleisli/ Co-authored-by: Arman Bilge --- core/src/main/scala/cats/data/Kleisli.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/Kleisli.scala b/core/src/main/scala/cats/data/Kleisli.scala index 96a1eac6d8..4047bfa596 100644 --- a/core/src/main/scala/cats/data/Kleisli.scala +++ b/core/src/main/scala/cats/data/Kleisli.scala @@ -625,7 +625,7 @@ sealed private[data] trait KleisliDecidable[F[_], D] def sum[A, B](fa: Kleisli[F, D, A], fb: Kleisli[F, D, B]): Kleisli[F, D, Either[A, B]] = Kleisli(d => F.sum(fa.run(d), fb.run(d))) - override val zero: ReaderT[F, D, Nothing] = + override val zero: Kleisli[F, D, Nothing] = Kleisli[F, D, Nothing](_ => F.zero) } From 6e75fbab3ab335909aedd8fcb163082b7901f770 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 5 Jul 2022 18:39:18 -0700 Subject: [PATCH 72/87] Undo some instance re-arranging that is no longer relevant --- core/src/main/scala/cats/data/OptionT.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index 413d033d4e..ea80cd102d 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -552,6 +552,11 @@ sealed abstract private[data] class OptionTInstances0 extends OptionTInstances1 implicit val F = F0 } + implicit def catsDataContravariantMonoidalForOptionT[F[_]](implicit + F0: ContravariantMonoidal[F] + ): ContravariantMonoidal[OptionT[F, *]] = + new OptionTContravariantMonoidal[F] { implicit val F = F0 } + implicit def catsDataMonoidKForOptionT[F[_]](implicit F0: Monad[F]): MonoidK[OptionT[F, *]] = new OptionTMonoidK[F] { implicit val F = F0 } @@ -579,11 +584,6 @@ sealed abstract private[data] class OptionTInstances1 extends OptionTInstances2 implicit def catsDataMonadErrorMonadForOptionT[F[_]](implicit F0: Monad[F]): MonadError[OptionT[F, *], Unit] = new OptionTMonadErrorMonad[F] { implicit val F = F0 } - - implicit def catsDataContravariantMonoidalForOptionT[F[_]](implicit - F0: ContravariantMonoidal[F] - ): ContravariantMonoidal[OptionT[F, *]] = - new OptionTContravariantMonoidal[F] { implicit val F = F0 } } sealed abstract private[data] class OptionTInstances2 extends OptionTInstances3 { From ebf2acf3d771977d7df31194f9ec33428adb2c36 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 5 Jul 2022 18:41:04 -0700 Subject: [PATCH 73/87] Eliminate unnecessary names match Co-authored-by: Arman Bilge --- core/src/main/scala/cats/data/WriterT.scala | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index c36ad02008..634d206b0b 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -765,12 +765,10 @@ sealed private[data] trait WriterTDecidable[F[_], L] override def sum[A, B](fa: WriterT[F, L, A], fb: WriterT[F, L, B]): WriterT[F, L, Either[A, B]] = WriterT( - F0.decide(fa.run, fb.run)((e: (L, Either[A, B])) => - e match { - case (l, Right(b)) => Right((l, b)) - case (l, Left(a)) => Left((l, a)) - } - ) + F0.decide(fa.run, fb.run) { + case (l, Right(b)) => Right((l, b)) + case (l, Left(a)) => Left((l, a)) + } ) override val zero: WriterT[F, L, Nothing] = WriterT[F, L, Nothing](F0.contramap[Nothing, (L, Nothing)](F0.zero)(_._2)) From bf5e3526ac56f7dcede874adcfc19e93796ae4a5 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 5 Jul 2022 18:43:08 -0700 Subject: [PATCH 74/87] Simpler bincompat strategy for Eq and Equiv --- core/src/main/scala/cats/instances/eq.scala | 29 ++------------- .../src/main/scala/cats/instances/equiv.scala | 36 ++----------------- 2 files changed, 4 insertions(+), 61 deletions(-) diff --git a/core/src/main/scala/cats/instances/eq.scala b/core/src/main/scala/cats/instances/eq.scala index 31dde7ef92..98e8c61565 100644 --- a/core/src/main/scala/cats/instances/eq.scala +++ b/core/src/main/scala/cats/instances/eq.scala @@ -22,7 +22,7 @@ package cats package instances -trait EqInstances extends kernel.instances.EqInstances with EqInstances0 { +trait EqInstances extends kernel.instances.EqInstances { implicit def catsDecidableForEq: Decidable[Eq] = new Decidable[Eq] { @@ -56,30 +56,5 @@ trait EqInstances extends kernel.instances.EqInstances with EqInstances0 { } val catsContravariantMonoidalForEq: ContravariantMonoidal[Eq] = - catsContravariantMonoidalForEqForBinCompat -} - -private[instances] trait EqInstances0 { - implicit def catsContravariantMonoidalForEqForBinCompat: ContravariantMonoidal[Eq] = - new ContravariantMonoidal[Eq] { - - /** - * Defaults to the trivial equivalence relation - * contracting the type to a point - */ - def unit: Eq[Unit] = Eq.allEqual - - /** - * Derive an `Eq` for `B` given an `Eq[A]` and a function `B => A`. - * - * Note: resulting instances are law-abiding only when the functions used are injective (represent a one-to-one mapping) - */ - def contramap[A, B](fa: Eq[A])(f: B => A): Eq[B] = - Eq.by(f)(fa) - - def product[A, B](fa: Eq[A], fb: Eq[B]): Eq[(A, B)] = - Eq.instance { (left, right) => - fa.eqv(left._1, right._1) && fb.eqv(left._2, right._2) - } - } + catsDecidableForEq } diff --git a/core/src/main/scala/cats/instances/equiv.scala b/core/src/main/scala/cats/instances/equiv.scala index d66924fd6d..37de377bfd 100644 --- a/core/src/main/scala/cats/instances/equiv.scala +++ b/core/src/main/scala/cats/instances/equiv.scala @@ -22,7 +22,7 @@ package cats package instances -trait EquivInstances extends EquivInstances0 { +trait EquivInstances { implicit def catsDecidableForEquiv: Decidable[Equiv] = new Decidable[Equiv] { @@ -65,37 +65,5 @@ trait EquivInstances extends EquivInstances0 { } val catsContravariantMonoidalForEquiv: ContravariantMonoidal[Equiv] = - catsContravariantMonoidalForEquivForBinCompat -} - -private[instances] trait EquivInstances0 { - implicit def catsContravariantMonoidalForEquivForBinCompat: ContravariantMonoidal[Equiv] = - new ContravariantMonoidal[Equiv] { - - /** - * Defaults to trivially contracting the type - * to a point - */ - val unit: Equiv[Unit] = - new Equiv[Unit] { - def equiv(x: Unit, y: Unit): Boolean = true - } - - /** - * Derive an `Equiv` for `B` given an `Equiv[A]` and a function `B => A`. - * - * Note: resulting instances are law-abiding only when the functions used are injective (represent a one-to-one mapping) - */ - def contramap[A, B](fa: Equiv[A])(f: B => A): Equiv[B] = - new Equiv[B] { - def equiv(l: B, r: B): Boolean = - fa.equiv(f(l), f(r)) - } - - def product[A, B](fa: Equiv[A], fb: Equiv[B]): Equiv[(A, B)] = - new Equiv[(A, B)] { - def equiv(l: (A, B), r: (A, B)): Boolean = - fa.equiv(l._1, r._1) && fb.equiv(l._2, r._2) - } - } + catsDecidableForEquiv } From 8d6143479d7bed3da8807f0d31817247ac6cae13 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 5 Jul 2022 18:51:53 -0700 Subject: [PATCH 75/87] Fix docsite a bit --- docs/typeclasses/decidable.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/typeclasses/decidable.md b/docs/typeclasses/decidable.md index ae2ccea68f..568da5b7e1 100644 --- a/docs/typeclasses/decidable.md +++ b/docs/typeclasses/decidable.md @@ -14,6 +14,8 @@ trait Decidable[F[_]] extends ContravariantMonoidal[F] { def decide[A, B, C](fa: F[A], fb: F[B])(f: C => Either[A, B]): F[C] = contramap(sum(fa, fb))(f) + + def lose[A](f: A => Nothing): F[A] = contramap[Nothing, A](zero)(f) } object Decidable { def apply[F[_]](implicit dec: Decidable[F]): Decidable[F] = From bcf4801409616e3320297c7d3c2750d4b9b43348 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 5 Jul 2022 18:52:13 -0700 Subject: [PATCH 76/87] Remove some odd instance scoping in tests --- tests/shared/src/test/scala/cats/tests/KleisliSuite.scala | 3 --- tests/shared/src/test/scala/cats/tests/OpSuite.scala | 5 ----- 2 files changed, 8 deletions(-) diff --git a/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala b/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala index 9e877e7ad0..893a7e5cf6 100644 --- a/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala @@ -140,9 +140,6 @@ class KleisliSuite extends CatsSuite { } { - implicit val catsDataContravariantMonoidalForKleisliLocal - : ContravariantMonoidal[Kleisli[Const[String, *], Int, *]] = - Kleisli.catsDataContravariantMonoidalForKleisli[Const[String, *], Int] checkAll("Kleisli[Const[String, *], MiniInt, *]", ContravariantMonoidalTests[Kleisli[Const[String, *], MiniInt, *]].contravariantMonoidal[Int, Int, Int] ) diff --git a/tests/shared/src/test/scala/cats/tests/OpSuite.scala b/tests/shared/src/test/scala/cats/tests/OpSuite.scala index 59bf6d26c3..d278e803de 100644 --- a/tests/shared/src/test/scala/cats/tests/OpSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/OpSuite.scala @@ -44,14 +44,11 @@ class OpSuite extends CatsSuite { } { - implicit val catsDataDecidableForOp: Decidable[Op[Function1, Int, *]] = Op.catsDataDecidableForOp[Function1, Int] checkAll("Op[Function1, Monoid, ?]", DecidableTests[Op[Function1, Int, *]].decidable[MiniInt, MiniInt, MiniInt]) checkAll("Decidable[Op[Function1, Monoid, ?]]", SerializableTests.serializable(Decidable[Op[Function1, Int, *]])) } { - implicit val catsDataContravariantMonoidalForOp: ContravariantMonoidal[Op[Function1, Int, *]] = - Op.catsDataContravariantMonoidalForOp[Function1, Int] checkAll("Op[Function1, Monoid, ?]", ContravariantMonoidalTests[Op[Function1, Int, *]].contravariantMonoidal[MiniInt, MiniInt, MiniInt] ) @@ -62,8 +59,6 @@ class OpSuite extends CatsSuite { } { - implicit val catsDataContravariantForOp: ContravariantMonoidal[Op[Function1, Unit, *]] = - Op.catsDataContravariantMonoidalForOp[Function1, Unit] checkAll("Op[Function1, Unit, ?]", ContravariantTests[Op[Function1, Unit, *]].contravariant[MiniInt, MiniInt, MiniInt] ) From 527444983cbf444a317626df6bfe66c19ef10ee9 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 5 Jul 2022 18:59:19 -0700 Subject: [PATCH 77/87] Remove companion object from docsite --- docs/typeclasses/decidable.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/typeclasses/decidable.md b/docs/typeclasses/decidable.md index 568da5b7e1..c24df9198a 100644 --- a/docs/typeclasses/decidable.md +++ b/docs/typeclasses/decidable.md @@ -17,10 +17,6 @@ trait Decidable[F[_]] extends ContravariantMonoidal[F] { def lose[A](f: A => Nothing): F[A] = contramap[Nothing, A](zero)(f) } -object Decidable { - def apply[F[_]](implicit dec: Decidable[F]): Decidable[F] = - dec -} ``` `sum` lets us implement the `decide` function. Note how `decide` says, no matter what the outcome of a possibly multi-outcome procedure, I can consume either outcome. @@ -54,8 +50,8 @@ def isEven(i: Int): Boolean = i % 2 == 0 def isDivisibleByThree(l: Long): Boolean = l % 3 == 0 def isEvenRightOrDivisibleThreeLeft: Either[Int, Long] => Boolean = - Decidable[* => Boolean].sum(isEven, isDivisibleByThree) + decideableForPredicates.sum(isEven, isDivisibleByThree) def isEvenRightAndDivisibleThreeLeft: ((Int, Long)) => Boolean = - Decidable[* => Boolean].product(isEven, isDivisibleByThree) + decideableForPredicates.product(isEven, isDivisibleByThree) ``` From e06a780a20edfd4032586788abae04ea7a7c7b23 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Tue, 5 Jul 2022 18:59:31 -0700 Subject: [PATCH 78/87] Define test Predicate instance via std instance --- .../shared/src/test/scala/cats/tests/Predicate.scala | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/shared/src/test/scala/cats/tests/Predicate.scala b/tests/shared/src/test/scala/cats/tests/Predicate.scala index 63fdafd206..78e5717160 100644 --- a/tests/shared/src/test/scala/cats/tests/Predicate.scala +++ b/tests/shared/src/test/scala/cats/tests/Predicate.scala @@ -22,6 +22,7 @@ package cats.tests import cats.Decidable +import cats.instances.function.catsStdDecidableForPredicate import cats.kernel.Eq import cats.laws.discipline.eq._ import cats.laws.discipline.ExhaustiveCheck @@ -31,14 +32,14 @@ case class Predicate[A](run: A => Boolean) object Predicate { implicit val decidablePredicate: Decidable[Predicate] = new Decidable[Predicate] { - def unit: Predicate[Unit] = Predicate[Unit](Function.const(false)) + def unit: Predicate[Unit] = Predicate[Unit](catsStdDecidableForPredicate.unit) def product[A, B](fa: Predicate[A], fb: Predicate[B]): Predicate[(A, B)] = - Predicate(x => fa.run(x._1) || fb.run(x._2)) + Predicate(catsStdDecidableForPredicate.product(fa.run, fb.run)) def contramap[A, B](fa: Predicate[A])(f: B => A): Predicate[B] = - Predicate(x => fa.run(f(x))) + Predicate(catsStdDecidableForPredicate.contramap(fa.run)(f)) def sum[A, B](fa: Predicate[A], fb: Predicate[B]): Predicate[Either[A, B]] = - Predicate(_.fold(fa.run, fb.run)) - def zero: Predicate[Nothing] = Predicate[Nothing](_ => true) + Predicate(catsStdDecidableForPredicate.sum(fa.run, fb.run)) + def zero: Predicate[Nothing] = Predicate[Nothing](catsStdDecidableForPredicate.zero) } implicit def eqPredicate[A: ExhaustiveCheck]: Eq[Predicate[A]] = From 09389263b0c30481c5ab3bc09d64969616b2e7af Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 11 Jul 2022 18:06:32 -0700 Subject: [PATCH 79/87] Law for `decide` consistency --- laws/src/main/scala/cats/laws/DecidableLaws.scala | 3 +++ laws/src/main/scala/cats/laws/discipline/DecidableTests.scala | 2 ++ 2 files changed, 5 insertions(+) diff --git a/laws/src/main/scala/cats/laws/DecidableLaws.scala b/laws/src/main/scala/cats/laws/DecidableLaws.scala index 42b3ad35cd..ac4a9555c1 100644 --- a/laws/src/main/scala/cats/laws/DecidableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecidableLaws.scala @@ -25,6 +25,9 @@ package laws trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { implicit override def F: Decidable[F] + def decideConsistency[A, B, C](fa: F[A], fb: F[B], f: C => Either[A, B]): IsEq[F[C]] = + F.decide(fa, fb)(f) <-> F.contramap(F.sum(fa, fb))(f) + def decidableDecideLeftIdentity[A](fa: F[A]): IsEq[F[A]] = F.decide(fa, F.trivial[A])(Left.apply[A, A]) <-> fa diff --git a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala index 16eb2da22a..986cd8c366 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala @@ -50,6 +50,8 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { val parents = Seq(contravariantMonoidal[A, B, C]) val bases = Seq.empty val props = Seq( + "decide consistency" -> + forAll(laws.decideConsistency[A, B, C] _), "decidable left identity" -> forAll(laws.decidableDecideLeftIdentity[A] _), "decidable right identity" -> From 9620658bd3898896e0328dcb70bff0de0209c56e Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 11 Jul 2022 19:08:43 -0700 Subject: [PATCH 80/87] Add a law for zero --- laws/src/main/scala/cats/laws/DecidableLaws.scala | 3 +++ .../src/main/scala/cats/laws/discipline/DecidableTests.scala | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/laws/src/main/scala/cats/laws/DecidableLaws.scala b/laws/src/main/scala/cats/laws/DecidableLaws.scala index ac4a9555c1..4d898d0601 100644 --- a/laws/src/main/scala/cats/laws/DecidableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecidableLaws.scala @@ -28,6 +28,9 @@ trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { def decideConsistency[A, B, C](fa: F[A], fb: F[B], f: C => Either[A, B]): IsEq[F[C]] = F.decide(fa, fb)(f) <-> F.contramap(F.sum(fa, fb))(f) + def decideRightIdentity[A](fa: F[A], f: A => Either[A, Nothing]): IsEq[F[A]] = + F.decide[A, Nothing, A](fa, F.zero)(f) <-> fa + def decidableDecideLeftIdentity[A](fa: F[A]): IsEq[F[A]] = F.decide(fa, F.trivial[A])(Left.apply[A, A]) <-> fa diff --git a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala index 986cd8c366..b6fd7dce44 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala @@ -23,7 +23,7 @@ package cats package laws package discipline -import org.scalacheck.{Arbitrary, Cogen} +import org.scalacheck.{Arbitrary, Cogen, Gen} import org.scalacheck.Prop._ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { @@ -49,9 +49,12 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { val name = "decideable" val parents = Seq(contravariantMonoidal[A, B, C]) val bases = Seq.empty + implicit def arbNothingFunc: Arbitrary[A => Either[A, Nothing]] = Arbitrary(Gen.const((a: A) => Left(a))) val props = Seq( "decide consistency" -> forAll(laws.decideConsistency[A, B, C] _), + "decide right identity (zero)" -> + forAll(laws.decideRightAbsorption[A] _), "decidable left identity" -> forAll(laws.decidableDecideLeftIdentity[A] _), "decidable right identity" -> From 019ebf73fbc5dfc3ea5edc56593089d443ee9a2b Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 11 Jul 2022 19:24:40 -0700 Subject: [PATCH 81/87] A couple identity laws --- laws/src/main/scala/cats/laws/DecidableLaws.scala | 5 ++++- .../main/scala/cats/laws/discipline/DecidableTests.scala | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/laws/src/main/scala/cats/laws/DecidableLaws.scala b/laws/src/main/scala/cats/laws/DecidableLaws.scala index 4d898d0601..27a63378ad 100644 --- a/laws/src/main/scala/cats/laws/DecidableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecidableLaws.scala @@ -28,7 +28,10 @@ trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { def decideConsistency[A, B, C](fa: F[A], fb: F[B], f: C => Either[A, B]): IsEq[F[C]] = F.decide(fa, fb)(f) <-> F.contramap(F.sum(fa, fb))(f) - def decideRightIdentity[A](fa: F[A], f: A => Either[A, Nothing]): IsEq[F[A]] = + def decideRightIdentity[A](fa: F[A], f: A => Either[Nothing, A]): IsEq[F[A]] = + F.decide[Nothing, A, A](F.zero, fa)(f) <-> fa + + def decideLeftIdentity[A](fa: F[A], f: A => Either[A, Nothing]): IsEq[F[A]] = F.decide[A, Nothing, A](fa, F.zero)(f) <-> fa def decidableDecideLeftIdentity[A](fa: F[A]): IsEq[F[A]] = diff --git a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala index b6fd7dce44..72089ab71d 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala @@ -49,12 +49,15 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { val name = "decideable" val parents = Seq(contravariantMonoidal[A, B, C]) val bases = Seq.empty - implicit def arbNothingFunc: Arbitrary[A => Either[A, Nothing]] = Arbitrary(Gen.const((a: A) => Left(a))) + implicit def arbNothingFuncLeft: Arbitrary[A => Either[A, Nothing]] = Arbitrary(Gen.const((a: A) => Left(a))) + implicit def arbNothingFuncRight: Arbitrary[A => Either[Nothing, A]] = Arbitrary(Gen.const((a: A) => Right(a))) val props = Seq( "decide consistency" -> forAll(laws.decideConsistency[A, B, C] _), "decide right identity (zero)" -> - forAll(laws.decideRightAbsorption[A] _), + forAll(laws.decideRightIdentity[A] _), + "decide left identity (zero)" -> + forAll(laws.decideLeftIdentity[A] _), "decidable left identity" -> forAll(laws.decidableDecideLeftIdentity[A] _), "decidable right identity" -> From a9e56b957b88c1e1e584b8ba47307ad4fd500c35 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 11 Jul 2022 19:42:57 -0700 Subject: [PATCH 82/87] Simplify zero identity laws They're kinda dumb but it's something I guess --- laws/src/main/scala/cats/laws/DecidableLaws.scala | 8 ++++---- .../main/scala/cats/laws/discipline/DecidableTests.scala | 4 +--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/laws/src/main/scala/cats/laws/DecidableLaws.scala b/laws/src/main/scala/cats/laws/DecidableLaws.scala index 27a63378ad..cb1bb1ca94 100644 --- a/laws/src/main/scala/cats/laws/DecidableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecidableLaws.scala @@ -28,11 +28,11 @@ trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { def decideConsistency[A, B, C](fa: F[A], fb: F[B], f: C => Either[A, B]): IsEq[F[C]] = F.decide(fa, fb)(f) <-> F.contramap(F.sum(fa, fb))(f) - def decideRightIdentity[A](fa: F[A], f: A => Either[Nothing, A]): IsEq[F[A]] = - F.decide[Nothing, A, A](F.zero, fa)(f) <-> fa + def decideRightIdentity[A](fa: F[A]): IsEq[F[A]] = + F.decide[Nothing, A, A](F.zero, fa)(Right.apply) <-> fa - def decideLeftIdentity[A](fa: F[A], f: A => Either[A, Nothing]): IsEq[F[A]] = - F.decide[A, Nothing, A](fa, F.zero)(f) <-> fa + def decideLeftIdentity[A](fa: F[A]): IsEq[F[A]] = + F.decide[A, Nothing, A](fa, F.zero)(Left.apply) <-> fa def decidableDecideLeftIdentity[A](fa: F[A]): IsEq[F[A]] = F.decide(fa, F.trivial[A])(Left.apply[A, A]) <-> fa diff --git a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala index 72089ab71d..0bcf4c035f 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala @@ -23,7 +23,7 @@ package cats package laws package discipline -import org.scalacheck.{Arbitrary, Cogen, Gen} +import org.scalacheck.{Arbitrary, Cogen} import org.scalacheck.Prop._ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { @@ -49,8 +49,6 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { val name = "decideable" val parents = Seq(contravariantMonoidal[A, B, C]) val bases = Seq.empty - implicit def arbNothingFuncLeft: Arbitrary[A => Either[A, Nothing]] = Arbitrary(Gen.const((a: A) => Left(a))) - implicit def arbNothingFuncRight: Arbitrary[A => Either[Nothing, A]] = Arbitrary(Gen.const((a: A) => Right(a))) val props = Seq( "decide consistency" -> forAll(laws.decideConsistency[A, B, C] _), From a60cadd17610fc13a3851af932d7bef26fedebfb Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Mon, 11 Jul 2022 19:56:43 -0700 Subject: [PATCH 83/87] Possibly rigged versions of the `Nothing` tests --- laws/src/main/scala/cats/laws/DecidableLaws.scala | 6 ++++++ .../main/scala/cats/laws/discipline/DecidableTests.scala | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/laws/src/main/scala/cats/laws/DecidableLaws.scala b/laws/src/main/scala/cats/laws/DecidableLaws.scala index cb1bb1ca94..7af50cb108 100644 --- a/laws/src/main/scala/cats/laws/DecidableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecidableLaws.scala @@ -25,9 +25,15 @@ package laws trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { implicit override def F: Decidable[F] + def loseConsistency[A](f: A => Nothing): IsEq[F[A]] = + F.lose(f) <-> F.contramap[Nothing, A](F.zero)(f) + def decideConsistency[A, B, C](fa: F[A], fb: F[B], f: C => Either[A, B]): IsEq[F[C]] = F.decide(fa, fb)(f) <-> F.contramap(F.sum(fa, fb))(f) + def decideRightAbsorption[A](fa: F[A]): IsEq[F[Nothing]] = + F.contramap[(A, Nothing), Nothing](F.product[A, Nothing](fa, F.zero))((n: Nothing) => (n: A, n)) <-> F.zero + def decideRightIdentity[A](fa: F[A]): IsEq[F[A]] = F.decide[Nothing, A, A](F.zero, fa)(Right.apply) <-> fa diff --git a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala index 0bcf4c035f..947f0b5b78 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala @@ -23,7 +23,7 @@ package cats package laws package discipline -import org.scalacheck.{Arbitrary, Cogen} +import org.scalacheck.{Arbitrary, Cogen, Gen} import org.scalacheck.Prop._ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { @@ -46,12 +46,18 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { iso: SemigroupalTests.Isomorphisms[F] ): RuleSet = new RuleSet { + implicit val ArbNothing: Arbitrary[Nothing => Nothing] = Arbitrary(Gen.const((n: Nothing) => n)) + implicit val eqNothing: Eq[F[Nothing]] = Eq.by[F[Nothing], Unit]((_: F[Nothing]) => ()) val name = "decideable" val parents = Seq(contravariantMonoidal[A, B, C]) val bases = Seq.empty val props = Seq( + "lose consistency" -> + forAll(laws.loseConsistency[Nothing] _), "decide consistency" -> forAll(laws.decideConsistency[A, B, C] _), + "decide right absorption" -> + forAll(laws.decideRightAbsorption[A] _), "decide right identity (zero)" -> forAll(laws.decideRightIdentity[A] _), "decide left identity (zero)" -> From 00a6cd92c44137b7d8d300a3171efd872b3da074 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Wed, 20 Jul 2022 20:06:53 -0700 Subject: [PATCH 84/87] Re-structure Nothing based constraints in tests --- .../cats/laws/discipline/DecidableTests.scala | 2 +- .../cats/laws/discipline/ExhaustiveCheck.scala | 3 +++ .../scala/cats/tests/ContravariantSuite.scala | 13 +++++++++---- .../src/test/scala/cats/tests/EqSuite.scala | 3 +++ .../src/test/scala/cats/tests/EquivSuite.scala | 6 +++++- .../test/scala/cats/tests/FunctionSuite.scala | 2 ++ .../src/test/scala/cats/tests/IdTSuite.scala | 2 ++ .../test/scala/cats/tests/KleisliSuite.scala | 4 ++++ .../test/scala/cats/tests/NestedSuite.scala | 1 + .../src/test/scala/cats/tests/OpSuite.scala | 2 ++ .../test/scala/cats/tests/Tuple2KSuite.scala | 18 +++++++++++------- 11 files changed, 43 insertions(+), 13 deletions(-) diff --git a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala index 947f0b5b78..6c8bce301d 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala @@ -43,11 +43,11 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { EqCC: Eq[F[Either[C, C]]], EqFEitABC: Eq[F[Either[Either[A, B], C]]], EqFTupAEitBC: Eq[F[(A, Either[B, C])]], + EqFNothing: Eq[F[Nothing]], iso: SemigroupalTests.Isomorphisms[F] ): RuleSet = new RuleSet { implicit val ArbNothing: Arbitrary[Nothing => Nothing] = Arbitrary(Gen.const((n: Nothing) => n)) - implicit val eqNothing: Eq[F[Nothing]] = Eq.by[F[Nothing], Unit]((_: F[Nothing]) => ()) val name = "decideable" val parents = Seq(contravariantMonoidal[A, B, C]) val bases = Seq.empty diff --git a/laws/src/main/scala/cats/laws/discipline/ExhaustiveCheck.scala b/laws/src/main/scala/cats/laws/discipline/ExhaustiveCheck.scala index 2a244f9a41..8de09b45ea 100644 --- a/laws/src/main/scala/cats/laws/discipline/ExhaustiveCheck.scala +++ b/laws/src/main/scala/cats/laws/discipline/ExhaustiveCheck.scala @@ -40,6 +40,9 @@ object ExhaustiveCheck { val allValues: List[A] = values } + implicit val catsLawExhaustiveCheckForNothing: ExhaustiveCheck[Nothing] = + instance[Nothing](List.empty[Nothing]) + implicit val catsLawsExhaustiveCheckForBoolean: ExhaustiveCheck[Boolean] = instance(List(false, true)) diff --git a/tests/shared/src/test/scala/cats/tests/ContravariantSuite.scala b/tests/shared/src/test/scala/cats/tests/ContravariantSuite.scala index 9640a59415..83fae30af4 100644 --- a/tests/shared/src/test/scala/cats/tests/ContravariantSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/ContravariantSuite.scala @@ -21,11 +21,13 @@ package cats.tests +import cats.Eq import cats.data.Const import cats.kernel.laws.discipline.{MonoidTests, SemigroupTests} import cats.kernel.{Monoid, Semigroup} import cats.laws.discipline.arbitrary._ import cats.laws.discipline.{DecidableTests, MiniInt} +import cats.laws.discipline.ExhaustiveCheck.catsLawExhaustiveCheckForNothing import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal} import org.scalacheck.Prop._ @@ -41,10 +43,13 @@ class ContravariantSuite extends CatsSuite { } } - checkAll( - "Decidable[Predicate]", - DecidableTests[Predicate].decidable[Boolean, Boolean, Boolean] - ) + { + implicit val eqForPredicateNothing: Eq[Predicate[Nothing]] = Predicate.eqPredicate[Nothing] + checkAll( + "Decidable[Predicate]", + DecidableTests[Predicate].decidable[Boolean, Boolean, Boolean] + ) + } { implicit val predicateMonoid: Monoid[Predicate[MiniInt]] = ContravariantMonoidal.monoid[Predicate, MiniInt] diff --git a/tests/shared/src/test/scala/cats/tests/EqSuite.scala b/tests/shared/src/test/scala/cats/tests/EqSuite.scala index bec95cebb1..da0ee653fd 100644 --- a/tests/shared/src/test/scala/cats/tests/EqSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/EqSuite.scala @@ -36,6 +36,9 @@ class EqSuite extends CatsSuite { ContravariantMonoidal[Eq] Decidable[Eq] + // Since equivalence on functions (Nothing, Nothing) => Boolean is + // equivalence on Nothing => Boolean it should be vacuously true + implicit val eqForEqNothing: Eq[Eq[Nothing]] = Eq.allEqual[Eq[Nothing]] checkAll("Eq", DecidableTests[Eq].decidable[MiniInt, Boolean, Boolean]) checkAll("Decidable[Eq]", SerializableTests.serializable(Decidable[Eq])) diff --git a/tests/shared/src/test/scala/cats/tests/EquivSuite.scala b/tests/shared/src/test/scala/cats/tests/EquivSuite.scala index e0ad16d1c3..7b7a526993 100644 --- a/tests/shared/src/test/scala/cats/tests/EquivSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/EquivSuite.scala @@ -21,7 +21,7 @@ package cats.tests -import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal, Decidable, Invariant, Semigroupal} +import cats.{Contravariant, ContravariantMonoidal, ContravariantSemigroupal, Decidable, Eq, Invariant, Semigroupal} import cats.laws.discipline.arbitrary._ import cats.laws.discipline._ import cats.laws.discipline.eq._ @@ -40,6 +40,10 @@ class EquivSuite extends CatsSuite { checkAll("ContravariantMonoidal[Equiv]", ContravariantMonoidalTests[Equiv].contravariantMonoidal[MiniInt, Boolean, Boolean] ) + + // Since equivalence on functions (Nothing, Nothing) => Boolean is + // equivalence on Nothing => Boolean it should be vacuously true + implicit val eqEquivNothing: Eq[Equiv[Nothing]] = Eq.allEqual[Equiv[Nothing]] checkAll("Decidable[Equiv]", DecidableTests[Equiv].decidable[MiniInt, Boolean, Boolean]) checkAll("Decidable[Equiv]", SerializableTests.serializable(Decidable[Equiv])) } diff --git a/tests/shared/src/test/scala/cats/tests/FunctionSuite.scala b/tests/shared/src/test/scala/cats/tests/FunctionSuite.scala index 8a29ee6cc2..59529ba72a 100644 --- a/tests/shared/src/test/scala/cats/tests/FunctionSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/FunctionSuite.scala @@ -186,6 +186,8 @@ class FunctionSuite extends CatsSuite { // Isos for Decidable implicit val isoCodomainBoolean: Isomorphisms[Function1[*, Boolean]] = SemigroupalTests.Isomorphisms.invariant[Function1[*, Boolean]] + // Vacuously true that all elements of the empty set are equivalent + implicit val eqNothingPreciates: Eq[Nothing => Boolean] = Eq.allEqual[Nothing => Boolean] checkAll("Function1[?, Boolean]", DecidableTests[Function1[*, Boolean]].decidable[MiniInt, MiniInt, MiniInt]) checkAll("Decidable[? => Boolean]", SerializableTests.serializable(Decidable[Function1[*, Boolean]])) diff --git a/tests/shared/src/test/scala/cats/tests/IdTSuite.scala b/tests/shared/src/test/scala/cats/tests/IdTSuite.scala index ad70a22057..625060dc46 100644 --- a/tests/shared/src/test/scala/cats/tests/IdTSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/IdTSuite.scala @@ -89,6 +89,8 @@ class IdTSuite extends CatsSuite { } { + // Predicates on Nothing are vacuously equivalent, because all vacuously true, and IdT of these are the same + implicit val eqPredicateNothing: Eq[IdT[Predicate, Nothing]] = Eq.allEqual[IdT[Predicate, Nothing]] checkAll("IdT[* => Boolean], ?]", DecidableTests[IdT[Predicate, *]].decidable[MiniInt, MiniInt, MiniInt]) checkAll("Decidable[IdT[* => Boolean, ?], ?]]", SerializableTests.serializable(Decidable[IdT[Predicate, *]])) } diff --git a/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala b/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala index 893a7e5cf6..879340d60b 100644 --- a/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala @@ -128,6 +128,10 @@ class KleisliSuite extends CatsSuite { checkAll("Alternative[Kleisli[Option, Int, *]]", SerializableTests.serializable(Alternative[Kleisli[Option, Int, *]])) { + // Kleisli[Predicate, MiniInt, Nothing]] == MiniInt => Predicate[Nothing] == MiniInt => (Nothing => Boolean) + // but all predicates on nothing are equivalent, so all such mappings are equivalent + implicit val eqKleisliPreciateNothing: Eq[Kleisli[Predicate, MiniInt, Nothing]] = + Eq.allEqual[Kleisli[Predicate, MiniInt, Nothing]] checkAll("Kleisli[Predicate, MiniInt, MiniInt]", DecidableTests[Kleisli[Predicate, MiniInt, *]].decidable[MiniInt, MiniInt, MiniInt] ) diff --git a/tests/shared/src/test/scala/cats/tests/NestedSuite.scala b/tests/shared/src/test/scala/cats/tests/NestedSuite.scala index 967a3510ce..903ee69e7b 100644 --- a/tests/shared/src/test/scala/cats/tests/NestedSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/NestedSuite.scala @@ -140,6 +140,7 @@ class NestedSuite extends CatsSuite { { // Applicative + Decidable functor composition + implicit val eqForOptionPredicateNothing: Eq[Nested[Option, Predicate, Nothing]] = Eq.allEqual checkAll("Nested[Option, Predicate, ?]", DecidableTests[Nested[Option, Predicate, *]].decidable[MiniInt, MiniInt, MiniInt] ) diff --git a/tests/shared/src/test/scala/cats/tests/OpSuite.scala b/tests/shared/src/test/scala/cats/tests/OpSuite.scala index d278e803de..5482a68321 100644 --- a/tests/shared/src/test/scala/cats/tests/OpSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/OpSuite.scala @@ -44,6 +44,8 @@ class OpSuite extends CatsSuite { } { + // Op[Function1, Monoid, Nothing] = Nothing => (A: Monoid) which is vacously equivalent + implicit val eqForOpFunction1Nothing: Eq[Op[Function1, Int, Nothing]] = Eq.allEqual checkAll("Op[Function1, Monoid, ?]", DecidableTests[Op[Function1, Int, *]].decidable[MiniInt, MiniInt, MiniInt]) checkAll("Decidable[Op[Function1, Monoid, ?]]", SerializableTests.serializable(Decidable[Op[Function1, Int, *]])) } diff --git a/tests/shared/src/test/scala/cats/tests/Tuple2KSuite.scala b/tests/shared/src/test/scala/cats/tests/Tuple2KSuite.scala index 5f3036d875..064f7681a0 100644 --- a/tests/shared/src/test/scala/cats/tests/Tuple2KSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/Tuple2KSuite.scala @@ -63,13 +63,17 @@ class Tuple2KSuite extends CatsSuite { SerializableTests.serializable(ContravariantMonoidal[λ[α => Tuple2K[Const[String, *], Const[Int, *], α]]]) ) - checkAll("Tuple2K[Predicate, Predicate, MiniInt]", - DecidableTests[Tuple2K[Predicate, Predicate, *]].decidable[MiniInt, MiniInt, MiniInt] - ) - checkAll( - "Decidable[Tuple2K[Predicate, Predicate, MiniInt]]", - SerializableTests.serializable(Decidable[Tuple2K[Predicate, Predicate, *]]) - ) + { + // Predicates on Nothing are vacuous, so their product are also + implicit val eqForTuple2KPredicateNothing: Eq[Tuple2K[Predicate, Predicate, Nothing]] = Eq.allEqual + checkAll("Tuple2K[Predicate, Predicate, MiniInt]", + DecidableTests[Tuple2K[Predicate, Predicate, *]].decidable[MiniInt, MiniInt, MiniInt] + ) + checkAll( + "Decidable[Tuple2K[Predicate, Predicate, MiniInt]]", + SerializableTests.serializable(Decidable[Tuple2K[Predicate, Predicate, *]]) + ) + } checkAll("Show[Tuple2K[Option, Option, Int]]", SerializableTests.serializable(Show[Tuple2K[Option, Option, Int]])) From 3ef22ed77bfcb253b6d68d3818da1e74e4057326 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Wed, 20 Jul 2022 20:44:33 -0700 Subject: [PATCH 85/87] Comment on weird instance, shrug shoulders --- tests/shared/src/test/scala/cats/tests/NestedSuite.scala | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/shared/src/test/scala/cats/tests/NestedSuite.scala b/tests/shared/src/test/scala/cats/tests/NestedSuite.scala index 903ee69e7b..3182369090 100644 --- a/tests/shared/src/test/scala/cats/tests/NestedSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/NestedSuite.scala @@ -140,6 +140,13 @@ class NestedSuite extends CatsSuite { { // Applicative + Decidable functor composition + // Now, you might think: + // Nested[Option, Predicate, Nothing] = Option[Predicate[Nothing]] = Option[Nothing => Boolean] + // If we have both Some and Some then equal, if we have both None then equal, else NOT equal + // since predicates on Nothing are vacuously equivalent. + // But since there are no values of `Some[Nothing]`, really this type is just... `None`. + // So they're all equal. The stronger instance (because of the trick arbitraries at play) + // ends up testing spurious values so it gets a bit wonky. implicit val eqForOptionPredicateNothing: Eq[Nested[Option, Predicate, Nothing]] = Eq.allEqual checkAll("Nested[Option, Predicate, ?]", DecidableTests[Nested[Option, Predicate, *]].decidable[MiniInt, MiniInt, MiniInt] From 0c9c09097c2ff88b543cd99fffdb38b0f6d17f4e Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Wed, 17 Aug 2022 20:57:15 -0700 Subject: [PATCH 86/87] Delete right absorption --- laws/src/main/scala/cats/laws/DecidableLaws.scala | 3 --- laws/src/main/scala/cats/laws/discipline/DecidableTests.scala | 2 -- 2 files changed, 5 deletions(-) diff --git a/laws/src/main/scala/cats/laws/DecidableLaws.scala b/laws/src/main/scala/cats/laws/DecidableLaws.scala index 7af50cb108..5cb0fed61b 100644 --- a/laws/src/main/scala/cats/laws/DecidableLaws.scala +++ b/laws/src/main/scala/cats/laws/DecidableLaws.scala @@ -31,9 +31,6 @@ trait DecidableLaws[F[_]] extends ContravariantMonoidalLaws[F] { def decideConsistency[A, B, C](fa: F[A], fb: F[B], f: C => Either[A, B]): IsEq[F[C]] = F.decide(fa, fb)(f) <-> F.contramap(F.sum(fa, fb))(f) - def decideRightAbsorption[A](fa: F[A]): IsEq[F[Nothing]] = - F.contramap[(A, Nothing), Nothing](F.product[A, Nothing](fa, F.zero))((n: Nothing) => (n: A, n)) <-> F.zero - def decideRightIdentity[A](fa: F[A]): IsEq[F[A]] = F.decide[Nothing, A, A](F.zero, fa)(Right.apply) <-> fa diff --git a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala index 6c8bce301d..09fc38ecfe 100644 --- a/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/DecidableTests.scala @@ -56,8 +56,6 @@ trait DecidableTests[F[_]] extends ContravariantMonoidalTests[F] { forAll(laws.loseConsistency[Nothing] _), "decide consistency" -> forAll(laws.decideConsistency[A, B, C] _), - "decide right absorption" -> - forAll(laws.decideRightAbsorption[A] _), "decide right identity (zero)" -> forAll(laws.decideRightIdentity[A] _), "decide left identity (zero)" -> From 70f42dfcd42b90d457e93e073cf51d7e079d21f2 Mon Sep 17 00:00:00 2001 From: Stephen Lazaro Date: Wed, 17 Aug 2022 21:32:42 -0700 Subject: [PATCH 87/87] Corrected Eq --- .../shared/src/test/scala/cats/tests/NestedSuite.scala | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/shared/src/test/scala/cats/tests/NestedSuite.scala b/tests/shared/src/test/scala/cats/tests/NestedSuite.scala index 3182369090..45a88e9549 100644 --- a/tests/shared/src/test/scala/cats/tests/NestedSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/NestedSuite.scala @@ -140,14 +140,8 @@ class NestedSuite extends CatsSuite { { // Applicative + Decidable functor composition - // Now, you might think: - // Nested[Option, Predicate, Nothing] = Option[Predicate[Nothing]] = Option[Nothing => Boolean] - // If we have both Some and Some then equal, if we have both None then equal, else NOT equal - // since predicates on Nothing are vacuously equivalent. - // But since there are no values of `Some[Nothing]`, really this type is just... `None`. - // So they're all equal. The stronger instance (because of the trick arbitraries at play) - // ends up testing spurious values so it gets a bit wonky. - implicit val eqForOptionPredicateNothing: Eq[Nested[Option, Predicate, Nothing]] = Eq.allEqual + // Only two values here, one for Some and one for None + implicit val eqForOptionPredicateNothing: Eq[Nested[Option, Predicate, Nothing]] = Eq.by(_.value.isDefined) checkAll("Nested[Option, Predicate, ?]", DecidableTests[Nested[Option, Predicate, *]].decidable[MiniInt, MiniInt, MiniInt] )