From 05a861d4fe10da9dca61049e1ab53420de34daa5 Mon Sep 17 00:00:00 2001 From: Kalra Date: Sun, 12 Apr 2020 20:33:42 +0800 Subject: [PATCH 1/7] added PartialFunction instance for Profunctor typeclass --- .../main/scala-2.12/cats/instances/all.scala | 3 ++ .../scala-2.12/cats/instances/package.scala | 1 + .../main/scala-2.13+/cats/instances/all.scala | 3 ++ .../scala-2.13+/cats/instances/package.scala | 1 + core/src/main/scala/cats/implicits.scala | 1 + .../cats/instances/partialFunction.scala | 28 +++++++++++++++++++ 6 files changed, 37 insertions(+) create mode 100644 core/src/main/scala/cats/instances/partialFunction.scala 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 bb949276a7..bcd63f61da 100644 --- a/core/src/main/scala-2.12/cats/instances/all.scala +++ b/core/src/main/scala-2.12/cats/instances/all.scala @@ -10,6 +10,7 @@ abstract class AllInstancesBinCompat with AllInstancesBinCompat4 with AllInstancesBinCompat5 with AllInstancesBinCompat6 + with AllInstancesBinCompat7 trait AllInstances extends AnyValInstances @@ -63,3 +64,5 @@ trait AllInstancesBinCompat4 extends SortedMapInstancesBinCompat1 with MapInstan trait AllInstancesBinCompat5 extends SortedSetInstancesBinCompat0 trait AllInstancesBinCompat6 extends SortedSetInstancesBinCompat1 with SortedMapInstancesBinCompat2 + +trait AllInstancesBinCompat7 extends PartialFunctionInstances 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 c35f425d9c..15afd68f17 100644 --- a/core/src/main/scala-2.12/cats/instances/package.scala +++ b/core/src/main/scala-2.12/cats/instances/package.scala @@ -16,6 +16,7 @@ package object instances { object float extends FloatInstances object finiteDuration extends CoreFiniteDurationInstances with FiniteDurationInstances object function extends FunctionInstances with FunctionInstancesBinCompat0 + object partialFunction extends PartialFunctionInstances object future extends FutureInstances object int extends IntInstances object invariant extends InvariantMonoidalInstances diff --git a/core/src/main/scala-2.13+/cats/instances/all.scala b/core/src/main/scala-2.13+/cats/instances/all.scala index 9c473746dc..4d6ece7dbf 100644 --- a/core/src/main/scala-2.13+/cats/instances/all.scala +++ b/core/src/main/scala-2.13+/cats/instances/all.scala @@ -10,6 +10,7 @@ abstract class AllInstancesBinCompat with AllInstancesBinCompat4 with AllInstancesBinCompat5 with AllInstancesBinCompat6 + with AllInstancesBinCompat7 trait AllInstances extends AnyValInstances @@ -65,3 +66,5 @@ trait AllInstancesBinCompat4 extends SortedMapInstancesBinCompat1 with MapInstan trait AllInstancesBinCompat5 extends SortedSetInstancesBinCompat0 trait AllInstancesBinCompat6 extends SortedSetInstancesBinCompat1 with SortedMapInstancesBinCompat2 + +trait AllInstancesBinCompat7 extends PartialFunctionInstances diff --git a/core/src/main/scala-2.13+/cats/instances/package.scala b/core/src/main/scala-2.13+/cats/instances/package.scala index ed42de4c2a..3d5588ae46 100644 --- a/core/src/main/scala-2.13+/cats/instances/package.scala +++ b/core/src/main/scala-2.13+/cats/instances/package.scala @@ -17,6 +17,7 @@ package object instances { object float extends FloatInstances object finiteDuration extends CoreFiniteDurationInstances with FiniteDurationInstances object function extends FunctionInstances with FunctionInstancesBinCompat0 + object partialFunction extends PartialFunctionInstances object future extends FutureInstances object int extends IntInstances object invariant extends InvariantMonoidalInstances diff --git a/core/src/main/scala/cats/implicits.scala b/core/src/main/scala/cats/implicits.scala index 5c2f3202b9..ec75993632 100644 --- a/core/src/main/scala/cats/implicits.scala +++ b/core/src/main/scala/cats/implicits.scala @@ -17,3 +17,4 @@ object implicits with instances.AllInstancesBinCompat4 with instances.AllInstancesBinCompat5 with instances.AllInstancesBinCompat6 + with instances.AllInstancesBinCompat7 diff --git a/core/src/main/scala/cats/instances/partialFunction.scala b/core/src/main/scala/cats/instances/partialFunction.scala new file mode 100644 index 0000000000..c87406f075 --- /dev/null +++ b/core/src/main/scala/cats/instances/partialFunction.scala @@ -0,0 +1,28 @@ +package cats.instances +import cats.arrow.Profunctor + +trait PartialFunctionInstances { + implicit val catsStdProFunctorForPartialFunction: Profunctor[PartialFunction] = new Profunctor[PartialFunction] { + + /** + * Contramap on the first type parameter and map on the second type parameter + * + * Example: + * {{{ + * scala> import cats.implicits._ + * scala> import cats.arrow.Profunctor + * scala> val fab: PartialFunction[Double, Double] = { case x => x + 0.3 } + * scala> val f: Int => Double = x => x.toDouble / 2 + * scala> val g: Double => Double = x => x * 3 + * scala> val h = Profunctor[PartialFunction].dimap(fab)(f)(g) + * scala> h(3) + * res0: Double = 5.4 + * }}} + */ + override def dimap[A, B, C, D](fab: PartialFunction[A, B])(f: C => A)(g: B => D): PartialFunction[C, D] = + new PartialFunction[C, D] { + override def isDefinedAt(c: C): Boolean = fab.isDefinedAt(f(c)) + override def apply(c: C): D = g(fab(f(c))) + } + } +} From c6e9f47a7d1188ab9c9db3e30a391dbd61b1a737 Mon Sep 17 00:00:00 2001 From: Kalra Date: Mon, 13 Apr 2020 10:39:09 +0800 Subject: [PATCH 2/7] updated doctest to use as extension method --- core/src/main/scala/cats/instances/partialFunction.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/instances/partialFunction.scala b/core/src/main/scala/cats/instances/partialFunction.scala index c87406f075..15db0af607 100644 --- a/core/src/main/scala/cats/instances/partialFunction.scala +++ b/core/src/main/scala/cats/instances/partialFunction.scala @@ -10,11 +10,10 @@ trait PartialFunctionInstances { * Example: * {{{ * scala> import cats.implicits._ - * scala> import cats.arrow.Profunctor * scala> val fab: PartialFunction[Double, Double] = { case x => x + 0.3 } * scala> val f: Int => Double = x => x.toDouble / 2 * scala> val g: Double => Double = x => x * 3 - * scala> val h = Profunctor[PartialFunction].dimap(fab)(f)(g) + * scala> val h = fab.dimap(f)(g) * scala> h(3) * res0: Double = 5.4 * }}} From cfb8eadf65cff0bad67e8344173d3faaedeede07 Mon Sep 17 00:00:00 2001 From: Kalra Date: Thu, 16 Apr 2020 12:37:39 +0800 Subject: [PATCH 3/7] added entire arrow heirarchy for PartialFunction --- core/src/main/scala/cats/Applicative.scala | 2 +- core/src/main/scala/cats/arrow/Arrow.scala | 3 + .../main/scala/cats/arrow/ArrowChoice.scala | 3 + core/src/main/scala/cats/arrow/Choice.scala | 3 + .../scala/cats/arrow/CommutativeArrow.scala | 3 + .../main/scala/cats/instances/function.scala | 9 +-- .../cats/instances/partialFunction.scala | 75 +++++++++++++------ .../main/scala/cats/laws/discipline/Eq.scala | 8 ++ .../cats/tests/PartialFunctionSuite.scala | 22 ++++++ 9 files changed, 101 insertions(+), 27 deletions(-) create mode 100644 tests/src/test/scala/cats/tests/PartialFunctionSuite.scala diff --git a/core/src/main/scala/cats/Applicative.scala b/core/src/main/scala/cats/Applicative.scala index 578159b155..b5a6fcea0e 100644 --- a/core/src/main/scala/cats/Applicative.scala +++ b/core/src/main/scala/cats/Applicative.scala @@ -202,7 +202,7 @@ object Applicative { * scala> import cats.Applicative.catsApplicativeForArrow * scala> val toLong: Int => Long = _.toLong * scala> val double: Int => Int = 2*_ - * scala> val f: Int => (Long, Int) = catsApplicativeForArrow.product(toLong, double) + * scala> val f: Int => (Long, Int) = catsApplicativeForArrow[Function1, Int].product(toLong, double) * scala> f(3) * res0: (Long, Int) = (3,6) * }}} diff --git a/core/src/main/scala/cats/arrow/Arrow.scala b/core/src/main/scala/cats/arrow/Arrow.scala index fca09c9e8f..f14aa17919 100644 --- a/core/src/main/scala/cats/arrow/Arrow.scala +++ b/core/src/main/scala/cats/arrow/Arrow.scala @@ -74,6 +74,9 @@ import scala.annotation.implicitNotFound object Arrow { + implicit val partialFunction: Arrow[PartialFunction] = + cats.instances.partialFunction.catsStdInstancesForArrowHierarchy + /****************************************************************************/ /* THE FOLLOWING CODE IS MANAGED BY SIMULACRUM; PLEASE DO NOT EDIT!!!! */ /****************************************************************************/ diff --git a/core/src/main/scala/cats/arrow/ArrowChoice.scala b/core/src/main/scala/cats/arrow/ArrowChoice.scala index e36fff4e38..b700096c3a 100644 --- a/core/src/main/scala/cats/arrow/ArrowChoice.scala +++ b/core/src/main/scala/cats/arrow/ArrowChoice.scala @@ -46,6 +46,9 @@ import scala.annotation.implicitNotFound object ArrowChoice { + implicit val partialFunction: ArrowChoice[PartialFunction] = + cats.instances.partialFunction.catsStdInstancesForArrowHierarchy + /****************************************************************************/ /* THE FOLLOWING CODE IS MANAGED BY SIMULACRUM; PLEASE DO NOT EDIT!!!! */ /****************************************************************************/ diff --git a/core/src/main/scala/cats/arrow/Choice.scala b/core/src/main/scala/cats/arrow/Choice.scala index 4b1147843b..67cf90f16e 100644 --- a/core/src/main/scala/cats/arrow/Choice.scala +++ b/core/src/main/scala/cats/arrow/Choice.scala @@ -50,6 +50,9 @@ import scala.annotation.implicitNotFound object Choice { + implicit val partialFunction: Choice[PartialFunction] = + cats.instances.partialFunction.catsStdInstancesForArrowHierarchy + /****************************************************************************/ /* THE FOLLOWING CODE IS MANAGED BY SIMULACRUM; PLEASE DO NOT EDIT!!!! */ /****************************************************************************/ diff --git a/core/src/main/scala/cats/arrow/CommutativeArrow.scala b/core/src/main/scala/cats/arrow/CommutativeArrow.scala index fca4d13514..4c0e55f93b 100644 --- a/core/src/main/scala/cats/arrow/CommutativeArrow.scala +++ b/core/src/main/scala/cats/arrow/CommutativeArrow.scala @@ -15,6 +15,9 @@ import scala.annotation.implicitNotFound object CommutativeArrow { + implicit val partialFunction: CommutativeArrow[PartialFunction] = + cats.instances.partialFunction.catsStdInstancesForArrowHierarchy + /****************************************************************************/ /* THE FOLLOWING CODE IS MANAGED BY SIMULACRUM; PLEASE DO NOT EDIT!!!! */ /****************************************************************************/ diff --git a/core/src/main/scala/cats/instances/function.scala b/core/src/main/scala/cats/instances/function.scala index a3c640661d..b45b658b93 100644 --- a/core/src/main/scala/cats/instances/function.scala +++ b/core/src/main/scala/cats/instances/function.scala @@ -136,11 +136,10 @@ sealed private[instances] trait Function1Instances extends Function1Instances0 { implicit val catsStdInstancesForFunction1: ArrowChoice[Function1] with CommutativeArrow[Function1] = new ArrowChoice[Function1] with CommutativeArrow[Function1] { - def choose[A, B, C, D](f: A => C)(g: B => D): Either[A, B] => Either[C, D] = - _ match { - case Left(a) => Left(f(a)) - case Right(b) => Right(g(b)) - } + def choose[A, B, C, D](f: A => C)(g: B => D): Either[A, B] => Either[C, D] = { + case Left(a) => Left(f(a)) + case Right(b) => Right(g(b)) + } def lift[A, B](f: A => B): A => B = f diff --git a/core/src/main/scala/cats/instances/partialFunction.scala b/core/src/main/scala/cats/instances/partialFunction.scala index 15db0af607..b0e119808a 100644 --- a/core/src/main/scala/cats/instances/partialFunction.scala +++ b/core/src/main/scala/cats/instances/partialFunction.scala @@ -1,27 +1,60 @@ package cats.instances -import cats.arrow.Profunctor +import cats.arrow.{ArrowChoice, CommutativeArrow} trait PartialFunctionInstances { - implicit val catsStdProFunctorForPartialFunction: Profunctor[PartialFunction] = new Profunctor[PartialFunction] { - /** - * Contramap on the first type parameter and map on the second type parameter - * - * Example: - * {{{ - * scala> import cats.implicits._ - * scala> val fab: PartialFunction[Double, Double] = { case x => x + 0.3 } - * scala> val f: Int => Double = x => x.toDouble / 2 - * scala> val g: Double => Double = x => x * 3 - * scala> val h = fab.dimap(f)(g) - * scala> h(3) - * res0: Double = 5.4 - * }}} - */ - override def dimap[A, B, C, D](fab: PartialFunction[A, B])(f: C => A)(g: B => D): PartialFunction[C, D] = - new PartialFunction[C, D] { - override def isDefinedAt(c: C): Boolean = fab.isDefinedAt(f(c)) - override def apply(c: C): D = g(fab(f(c))) + implicit val catsStdInstancesForArrowHierarchy: ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] = + new ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] { + + /** + * {{{ + * scala> import cats.arrow.Arrow + * scala> import cats.syntax.arrowChoice._ + * scala> val toLong: PartialFunction[Int, Long] = Arrow[PartialFunction].lift(_.toLong) + * scala> val toDouble: PartialFunction[Float, Double] = Arrow[PartialFunction].lift(_.toDouble) + * scala> val f: PartialFunction[Either[Int, Float], Either[Long, Double]] = toLong +++ toDouble + * scala> f(Left(3)) + * res0: Either[Long,Double] = Left(3) + * scala> f(Right(3)) + * res1: Either[Long,Double] = Right(3.0) + * }}} + */ + override def choose[A, B, C, D](f: PartialFunction[A, C])( + g: PartialFunction[B, D] + ): PartialFunction[Either[A, B], Either[C, D]] = { + case Left(a) if f.isDefinedAt(a) => Left(f(a)) + case Right(b) if g.isDefinedAt(b) => Right(g(b)) + } + + override def lift[A, B](f: A => B): PartialFunction[A, B] = { case a if a.isInstanceOf[A] => f(a) } + + /** + * Create a new `F` that takes two inputs, but only modifies the first input + * + * Example: + * {{{ + * scala> import cats.arrow.Arrow + * scala> import cats.arrow.Strong + * scala> import cats.implicits._ + * scala> val f: PartialFunction[Int, Int] = Arrow[PartialFunction].lift(_ * 2) + * scala> val fab = Strong[PartialFunction].first[Int,Int,Int](f) + * scala> fab((2,3)) + * res0: (Int, Int) = (4,3) + * }}} + */ + override def first[A, B, C](fa: PartialFunction[A, B]): PartialFunction[(A, C), (B, C)] = { + case (a, c) if fa.isDefinedAt(a) => (fa(a), c) + } + + override def split[A, B, C, D]( + f: PartialFunction[A, B], + g: PartialFunction[C, D] + ): PartialFunction[(A, C), (B, D)] = { + case (a, c) if f.isDefinedAt(a) && g.isDefinedAt(c) => (f(a), g(c)) + } + + override def compose[A, B, C](f: PartialFunction[B, C], g: PartialFunction[A, B]): PartialFunction[A, C] = { + case a if g.isDefinedAt(a) && f.isDefinedAt(g(a)) => f(g(a)) } - } + } } diff --git a/laws/src/main/scala/cats/laws/discipline/Eq.scala b/laws/src/main/scala/cats/laws/discipline/Eq.scala index e2938add46..a1f2b12780 100644 --- a/laws/src/main/scala/cats/laws/discipline/Eq.scala +++ b/laws/src/main/scala/cats/laws/discipline/Eq.scala @@ -22,6 +22,14 @@ object eq { implicit def catsLawsEqForFn2[A, B, C](implicit ev: Eq[((A, B)) => C]): Eq[(A, B) => C] = Eq.by((_: (A, B) => C).tupled) + implicit def catsLawsEqForPartialFunctionExhaustive[A, B](implicit A: ExhaustiveCheck[A], + B: Eq[B]): Eq[PartialFunction[A, B]] = + Eq.instance((f, g) => + A.allValues + .filter(a => f.isDefinedAt(a) || g.isDefinedAt(a)) + .forall(a => f.isDefinedAt(a) && g.isDefinedAt(a) && B.eqv(f(a), g(a))) + ) + implicit def catsLawsEqForAndThen[A, B](implicit eqAB: Eq[A => B]): Eq[AndThen[A, B]] = Eq.by[AndThen[A, B], A => B](identity) diff --git a/tests/src/test/scala/cats/tests/PartialFunctionSuite.scala b/tests/src/test/scala/cats/tests/PartialFunctionSuite.scala new file mode 100644 index 0000000000..7350dea071 --- /dev/null +++ b/tests/src/test/scala/cats/tests/PartialFunctionSuite.scala @@ -0,0 +1,22 @@ +package cats.tests +import cats.arrow.{ArrowChoice, Choice, CommutativeArrow} +import cats.kernel.laws.discipline.SerializableTests +import cats.laws.discipline.arbitrary._ +import cats.laws.discipline.eq._ +import cats.laws.discipline.{ArrowChoiceTests, ChoiceTests, CommutativeArrowTests, MiniInt} + +class PartialFunctionSuite extends CatsSuite { + checkAll( + "PartialFunction", + CommutativeArrowTests[PartialFunction].commutativeArrow[MiniInt, MiniInt, MiniInt, MiniInt, MiniInt, MiniInt] + ) + checkAll("Arrow[PartialFunction]", SerializableTests.serializable(CommutativeArrow[PartialFunction])) + + checkAll("PartialFunction", ChoiceTests[PartialFunction].choice[MiniInt, Boolean, Int, Long]) + checkAll("Choice[PartialFunction]", SerializableTests.serializable(Choice[PartialFunction])) + + checkAll("PartialFunction", + ArrowChoiceTests[PartialFunction].arrowChoice[MiniInt, MiniInt, MiniInt, MiniInt, MiniInt, MiniInt]) + checkAll("ArrowChoice[PartialFunction]", SerializableTests.serializable(ArrowChoice[PartialFunction])) + +} From 6af528d27a06172d3a42279dc70695d49dca2497 Mon Sep 17 00:00:00 2001 From: Kalra Date: Wed, 3 Jun 2020 23:57:22 +0800 Subject: [PATCH 4/7] addressed review feedback, moved implicits to the top of the hierarchy (available to all) --- core/src/main/scala/cats/arrow/Arrow.scala | 3 --- .../main/scala/cats/arrow/ArrowChoice.scala | 3 --- core/src/main/scala/cats/arrow/Choice.scala | 3 --- .../scala/cats/arrow/CommutativeArrow.scala | 3 --- core/src/main/scala/cats/arrow/Compose.scala | 7 +++++-- .../main/scala/cats/arrow/Profunctor.scala | 5 ++++- .../cats/instances/partialFunction.scala | 10 +++++----- kernel/src/main/scala/cats/kernel/Eq.scala | 6 ++++-- .../main/scala/cats/laws/discipline/Eq.scala | 12 ++++------- .../cats/tests/PartialFunctionSuite.scala | 20 +++++++++---------- 10 files changed, 32 insertions(+), 40 deletions(-) diff --git a/core/src/main/scala/cats/arrow/Arrow.scala b/core/src/main/scala/cats/arrow/Arrow.scala index f14aa17919..fca09c9e8f 100644 --- a/core/src/main/scala/cats/arrow/Arrow.scala +++ b/core/src/main/scala/cats/arrow/Arrow.scala @@ -74,9 +74,6 @@ import scala.annotation.implicitNotFound object Arrow { - implicit val partialFunction: Arrow[PartialFunction] = - cats.instances.partialFunction.catsStdInstancesForArrowHierarchy - /****************************************************************************/ /* THE FOLLOWING CODE IS MANAGED BY SIMULACRUM; PLEASE DO NOT EDIT!!!! */ /****************************************************************************/ diff --git a/core/src/main/scala/cats/arrow/ArrowChoice.scala b/core/src/main/scala/cats/arrow/ArrowChoice.scala index b700096c3a..e36fff4e38 100644 --- a/core/src/main/scala/cats/arrow/ArrowChoice.scala +++ b/core/src/main/scala/cats/arrow/ArrowChoice.scala @@ -46,9 +46,6 @@ import scala.annotation.implicitNotFound object ArrowChoice { - implicit val partialFunction: ArrowChoice[PartialFunction] = - cats.instances.partialFunction.catsStdInstancesForArrowHierarchy - /****************************************************************************/ /* THE FOLLOWING CODE IS MANAGED BY SIMULACRUM; PLEASE DO NOT EDIT!!!! */ /****************************************************************************/ diff --git a/core/src/main/scala/cats/arrow/Choice.scala b/core/src/main/scala/cats/arrow/Choice.scala index 67cf90f16e..4b1147843b 100644 --- a/core/src/main/scala/cats/arrow/Choice.scala +++ b/core/src/main/scala/cats/arrow/Choice.scala @@ -50,9 +50,6 @@ import scala.annotation.implicitNotFound object Choice { - implicit val partialFunction: Choice[PartialFunction] = - cats.instances.partialFunction.catsStdInstancesForArrowHierarchy - /****************************************************************************/ /* THE FOLLOWING CODE IS MANAGED BY SIMULACRUM; PLEASE DO NOT EDIT!!!! */ /****************************************************************************/ diff --git a/core/src/main/scala/cats/arrow/CommutativeArrow.scala b/core/src/main/scala/cats/arrow/CommutativeArrow.scala index 4c0e55f93b..fca4d13514 100644 --- a/core/src/main/scala/cats/arrow/CommutativeArrow.scala +++ b/core/src/main/scala/cats/arrow/CommutativeArrow.scala @@ -15,9 +15,6 @@ import scala.annotation.implicitNotFound object CommutativeArrow { - implicit val partialFunction: CommutativeArrow[PartialFunction] = - cats.instances.partialFunction.catsStdInstancesForArrowHierarchy - /****************************************************************************/ /* THE FOLLOWING CODE IS MANAGED BY SIMULACRUM; PLEASE DO NOT EDIT!!!! */ /****************************************************************************/ diff --git a/core/src/main/scala/cats/arrow/Compose.scala b/core/src/main/scala/cats/arrow/Compose.scala index c6b767f75c..e05a9922aa 100644 --- a/core/src/main/scala/cats/arrow/Compose.scala +++ b/core/src/main/scala/cats/arrow/Compose.scala @@ -41,9 +41,12 @@ import scala.annotation.implicitNotFound } object Compose { - implicit def catsInstancesForFunction1: ArrowChoice[Function1] with CommutativeArrow[Function1] = + implicit val catsInstancesForFunction1: ArrowChoice[Function1] with CommutativeArrow[Function1] = cats.instances.function.catsStdInstancesForFunction1 - implicit def catsComposeForMap: Compose[Map] = cats.instances.map.catsStdComposeForMap + implicit val catsComposeForMap: Compose[Map] = cats.instances.map.catsStdComposeForMap + + implicit val catsInstancesForPartialFunction: ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] = + cats.instances.partialFunction.catsStdInstancesForPartialFunction /****************************************************************************/ /* THE FOLLOWING CODE IS MANAGED BY SIMULACRUM; PLEASE DO NOT EDIT!!!! */ diff --git a/core/src/main/scala/cats/arrow/Profunctor.scala b/core/src/main/scala/cats/arrow/Profunctor.scala index fa4753b078..5086c561dc 100644 --- a/core/src/main/scala/cats/arrow/Profunctor.scala +++ b/core/src/main/scala/cats/arrow/Profunctor.scala @@ -44,9 +44,12 @@ import scala.annotation.implicitNotFound } object Profunctor { - implicit def catsStrongForFunction1: Strong[Function1] = + implicit val catsStrongForFunction1: Strong[Function1] = cats.instances.function.catsStdInstancesForFunction1 + implicit val catsStrongForPartialFunction: Strong[PartialFunction] = + cats.instances.partialFunction.catsStdInstancesForPartialFunction + /****************************************************************************/ /* THE FOLLOWING CODE IS MANAGED BY SIMULACRUM; PLEASE DO NOT EDIT!!!! */ /****************************************************************************/ diff --git a/core/src/main/scala/cats/instances/partialFunction.scala b/core/src/main/scala/cats/instances/partialFunction.scala index b0e119808a..bdaf98bf1f 100644 --- a/core/src/main/scala/cats/instances/partialFunction.scala +++ b/core/src/main/scala/cats/instances/partialFunction.scala @@ -3,7 +3,7 @@ import cats.arrow.{ArrowChoice, CommutativeArrow} trait PartialFunctionInstances { - implicit val catsStdInstancesForArrowHierarchy: ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] = + implicit val catsStdInstancesForPartialFunction: ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] = new ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] { /** @@ -19,14 +19,14 @@ trait PartialFunctionInstances { * res1: Either[Long,Double] = Right(3.0) * }}} */ - override def choose[A, B, C, D](f: PartialFunction[A, C])( - g: PartialFunction[B, D] - ): PartialFunction[Either[A, B], Either[C, D]] = { + override def choose[A, B, C, D]( + f: PartialFunction[A, C] + )(g: PartialFunction[B, D]): PartialFunction[Either[A, B], Either[C, D]] = { case Left(a) if f.isDefinedAt(a) => Left(f(a)) case Right(b) if g.isDefinedAt(b) => Right(g(b)) } - override def lift[A, B](f: A => B): PartialFunction[A, B] = { case a if a.isInstanceOf[A] => f(a) } + override def lift[A, B](f: A => B): PartialFunction[A, B] = { case a => f(a) } /** * Create a new `F` that takes two inputs, but only modifies the first input diff --git a/kernel/src/main/scala/cats/kernel/Eq.scala b/kernel/src/main/scala/cats/kernel/Eq.scala index 554ca74bd0..b1786dc46e 100644 --- a/kernel/src/main/scala/cats/kernel/Eq.scala +++ b/kernel/src/main/scala/cats/kernel/Eq.scala @@ -1,12 +1,14 @@ package cats.kernel import java.util.UUID + +import cats.kernel.compat.scalaVersionSpecific._ + import scala.collection.immutable.{BitSet, Queue, SortedMap, SortedSet} import scala.concurrent.duration.{Duration, FiniteDuration} import scala.math.Equiv -import scala.{specialized => sp} import scala.util.{Failure, Success, Try} -import compat.scalaVersionSpecific._ +import scala.{specialized => sp} /** * A type class used to determine equality between 2 instances of the same diff --git a/laws/src/main/scala/cats/laws/discipline/Eq.scala b/laws/src/main/scala/cats/laws/discipline/Eq.scala index a1f2b12780..cf13b19855 100644 --- a/laws/src/main/scala/cats/laws/discipline/Eq.scala +++ b/laws/src/main/scala/cats/laws/discipline/Eq.scala @@ -2,13 +2,10 @@ package cats package laws package discipline -import cats.data.RepresentableStore -import cats.Eq -import cats.data.AndThen +import cats.data.{AndThen, RepresentableStore} import cats.instances.boolean._ import cats.instances.int._ import cats.instances.string._ -import cats.instances.tuple._ import cats.kernel._ import cats.platform.Platform import cats.syntax.eq._ @@ -22,12 +19,11 @@ object eq { implicit def catsLawsEqForFn2[A, B, C](implicit ev: Eq[((A, B)) => C]): Eq[(A, B) => C] = Eq.by((_: (A, B) => C).tupled) - implicit def catsLawsEqForPartialFunctionExhaustive[A, B](implicit A: ExhaustiveCheck[A], - B: Eq[B]): Eq[PartialFunction[A, B]] = + implicit def catsLawsEqForPartialFunctionExhaustive[A: ExhaustiveCheck, B: Eq]: Eq[PartialFunction[A, B]] = Eq.instance((f, g) => - A.allValues + ExhaustiveCheck[A].allValues .filter(a => f.isDefinedAt(a) || g.isDefinedAt(a)) - .forall(a => f.isDefinedAt(a) && g.isDefinedAt(a) && B.eqv(f(a), g(a))) + .forall(a => f.isDefinedAt(a) && g.isDefinedAt(a) && Eq[B].eqv(f(a), g(a))) ) implicit def catsLawsEqForAndThen[A, B](implicit eqAB: Eq[A => B]): Eq[AndThen[A, B]] = diff --git a/tests/src/test/scala/cats/tests/PartialFunctionSuite.scala b/tests/src/test/scala/cats/tests/PartialFunctionSuite.scala index 7350dea071..d07ac57121 100644 --- a/tests/src/test/scala/cats/tests/PartialFunctionSuite.scala +++ b/tests/src/test/scala/cats/tests/PartialFunctionSuite.scala @@ -1,22 +1,22 @@ package cats.tests -import cats.arrow.{ArrowChoice, Choice, CommutativeArrow} +import cats.arrow.{ArrowChoice, CommutativeArrow} import cats.kernel.laws.discipline.SerializableTests import cats.laws.discipline.arbitrary._ import cats.laws.discipline.eq._ -import cats.laws.discipline.{ArrowChoiceTests, ChoiceTests, CommutativeArrowTests, MiniInt} +import cats.laws.discipline.{ArrowChoiceTests, CommutativeArrowTests, MiniInt} class PartialFunctionSuite extends CatsSuite { + + checkAll("ArrowChoice[PartialFunction]", SerializableTests.serializable(ArrowChoice[PartialFunction])) + + checkAll("PartialFunction", + ArrowChoiceTests[PartialFunction].arrowChoice[MiniInt, MiniInt, MiniInt, MiniInt, MiniInt, MiniInt] + ) + + checkAll("CommutativeArrow[PartialFunction]", SerializableTests.serializable(CommutativeArrow[PartialFunction])) checkAll( "PartialFunction", CommutativeArrowTests[PartialFunction].commutativeArrow[MiniInt, MiniInt, MiniInt, MiniInt, MiniInt, MiniInt] ) - checkAll("Arrow[PartialFunction]", SerializableTests.serializable(CommutativeArrow[PartialFunction])) - - checkAll("PartialFunction", ChoiceTests[PartialFunction].choice[MiniInt, Boolean, Int, Long]) - checkAll("Choice[PartialFunction]", SerializableTests.serializable(Choice[PartialFunction])) - - checkAll("PartialFunction", - ArrowChoiceTests[PartialFunction].arrowChoice[MiniInt, MiniInt, MiniInt, MiniInt, MiniInt, MiniInt]) - checkAll("ArrowChoice[PartialFunction]", SerializableTests.serializable(ArrowChoice[PartialFunction])) } From 982c6522e3766e8baf715349146edeb031c524fc Mon Sep 17 00:00:00 2001 From: Kalra Date: Thu, 4 Jun 2020 09:53:53 +0800 Subject: [PATCH 5/7] added back instance check when lifting a function to partialFunction --- core/src/main/scala/cats/instances/partialFunction.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/instances/partialFunction.scala b/core/src/main/scala/cats/instances/partialFunction.scala index bdaf98bf1f..32b798e52f 100644 --- a/core/src/main/scala/cats/instances/partialFunction.scala +++ b/core/src/main/scala/cats/instances/partialFunction.scala @@ -26,7 +26,7 @@ trait PartialFunctionInstances { case Right(b) if g.isDefinedAt(b) => Right(g(b)) } - override def lift[A, B](f: A => B): PartialFunction[A, B] = { case a => f(a) } + override def lift[A, B](f: A => B): PartialFunction[A, B] = { case a if a.isInstanceOf[A] => f(a) } /** * Create a new `F` that takes two inputs, but only modifies the first input From e815d83a05dd82da8601c7b8fa5a63e004f60f41 Mon Sep 17 00:00:00 2001 From: Kalra Date: Fri, 12 Jun 2020 00:29:30 +0800 Subject: [PATCH 6/7] addressed review feedback, have `val` as `def` instead --- core/src/main/scala/cats/arrow/Compose.scala | 6 +++--- core/src/main/scala/cats/arrow/Profunctor.scala | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/cats/arrow/Compose.scala b/core/src/main/scala/cats/arrow/Compose.scala index e05a9922aa..70a5fffd61 100644 --- a/core/src/main/scala/cats/arrow/Compose.scala +++ b/core/src/main/scala/cats/arrow/Compose.scala @@ -41,11 +41,11 @@ import scala.annotation.implicitNotFound } object Compose { - implicit val catsInstancesForFunction1: ArrowChoice[Function1] with CommutativeArrow[Function1] = + implicit def catsInstancesForFunction1: ArrowChoice[Function1] with CommutativeArrow[Function1] = cats.instances.function.catsStdInstancesForFunction1 - implicit val catsComposeForMap: Compose[Map] = cats.instances.map.catsStdComposeForMap + implicit def catsComposeForMap: Compose[Map] = cats.instances.map.catsStdComposeForMap - implicit val catsInstancesForPartialFunction: ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] = + implicit def catsInstancesForPartialFunction: ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] = cats.instances.partialFunction.catsStdInstancesForPartialFunction /****************************************************************************/ diff --git a/core/src/main/scala/cats/arrow/Profunctor.scala b/core/src/main/scala/cats/arrow/Profunctor.scala index 5086c561dc..c5fa823583 100644 --- a/core/src/main/scala/cats/arrow/Profunctor.scala +++ b/core/src/main/scala/cats/arrow/Profunctor.scala @@ -44,10 +44,10 @@ import scala.annotation.implicitNotFound } object Profunctor { - implicit val catsStrongForFunction1: Strong[Function1] = + implicit def catsStrongForFunction1: Strong[Function1] = cats.instances.function.catsStdInstancesForFunction1 - implicit val catsStrongForPartialFunction: Strong[PartialFunction] = + implicit def catsStrongForPartialFunction: Strong[PartialFunction] = cats.instances.partialFunction.catsStdInstancesForPartialFunction /****************************************************************************/ From 4fd89272ba41cf5ed989c840262ce3076a8df80a Mon Sep 17 00:00:00 2001 From: Kalra Date: Fri, 12 Jun 2020 19:52:57 +0800 Subject: [PATCH 7/7] updated to have PartialFunctionInstances mixed in with AllInstances; improved doctests with less imports now needed --- core/src/main/scala-2.12/cats/instances/all.scala | 4 +--- core/src/main/scala-2.13+/cats/instances/all.scala | 4 +--- core/src/main/scala/cats/implicits.scala | 1 - .../main/scala/cats/instances/partialFunction.scala | 12 ++++++++---- 4 files changed, 10 insertions(+), 11 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 bcd63f61da..e9451a80be 100644 --- a/core/src/main/scala-2.12/cats/instances/all.scala +++ b/core/src/main/scala-2.12/cats/instances/all.scala @@ -10,7 +10,6 @@ abstract class AllInstancesBinCompat with AllInstancesBinCompat4 with AllInstancesBinCompat5 with AllInstancesBinCompat6 - with AllInstancesBinCompat7 trait AllInstances extends AnyValInstances @@ -44,6 +43,7 @@ trait AllInstances with TupleInstances with UUIDInstances with VectorInstances + with PartialFunctionInstances trait AllInstancesBinCompat0 extends FunctionInstancesBinCompat0 with Tuple2InstancesBinCompat0 @@ -64,5 +64,3 @@ trait AllInstancesBinCompat4 extends SortedMapInstancesBinCompat1 with MapInstan trait AllInstancesBinCompat5 extends SortedSetInstancesBinCompat0 trait AllInstancesBinCompat6 extends SortedSetInstancesBinCompat1 with SortedMapInstancesBinCompat2 - -trait AllInstancesBinCompat7 extends PartialFunctionInstances diff --git a/core/src/main/scala-2.13+/cats/instances/all.scala b/core/src/main/scala-2.13+/cats/instances/all.scala index 4d6ece7dbf..ea187d753f 100644 --- a/core/src/main/scala-2.13+/cats/instances/all.scala +++ b/core/src/main/scala-2.13+/cats/instances/all.scala @@ -10,7 +10,6 @@ abstract class AllInstancesBinCompat with AllInstancesBinCompat4 with AllInstancesBinCompat5 with AllInstancesBinCompat6 - with AllInstancesBinCompat7 trait AllInstances extends AnyValInstances @@ -46,6 +45,7 @@ trait AllInstances with TupleInstances with UUIDInstances with VectorInstances + with PartialFunctionInstances trait AllInstancesBinCompat0 extends FunctionInstancesBinCompat0 with Tuple2InstancesBinCompat0 @@ -66,5 +66,3 @@ trait AllInstancesBinCompat4 extends SortedMapInstancesBinCompat1 with MapInstan trait AllInstancesBinCompat5 extends SortedSetInstancesBinCompat0 trait AllInstancesBinCompat6 extends SortedSetInstancesBinCompat1 with SortedMapInstancesBinCompat2 - -trait AllInstancesBinCompat7 extends PartialFunctionInstances diff --git a/core/src/main/scala/cats/implicits.scala b/core/src/main/scala/cats/implicits.scala index ec75993632..5c2f3202b9 100644 --- a/core/src/main/scala/cats/implicits.scala +++ b/core/src/main/scala/cats/implicits.scala @@ -17,4 +17,3 @@ object implicits with instances.AllInstancesBinCompat4 with instances.AllInstancesBinCompat5 with instances.AllInstancesBinCompat6 - with instances.AllInstancesBinCompat7 diff --git a/core/src/main/scala/cats/instances/partialFunction.scala b/core/src/main/scala/cats/instances/partialFunction.scala index 32b798e52f..98a0bec94c 100644 --- a/core/src/main/scala/cats/instances/partialFunction.scala +++ b/core/src/main/scala/cats/instances/partialFunction.scala @@ -3,7 +3,13 @@ import cats.arrow.{ArrowChoice, CommutativeArrow} trait PartialFunctionInstances { - implicit val catsStdInstancesForPartialFunction: ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] = + implicit def catsStdInstancesForPartialFunction: ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] = + PartialFunctionInstances.instance +} + +private object PartialFunctionInstances { + + private val instance: ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] = new ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] { /** @@ -34,10 +40,8 @@ trait PartialFunctionInstances { * Example: * {{{ * scala> import cats.arrow.Arrow - * scala> import cats.arrow.Strong - * scala> import cats.implicits._ * scala> val f: PartialFunction[Int, Int] = Arrow[PartialFunction].lift(_ * 2) - * scala> val fab = Strong[PartialFunction].first[Int,Int,Int](f) + * scala> val fab = Arrow[PartialFunction].first[Int,Int,Int](f) * scala> fab((2,3)) * res0: (Int, Int) = (4,3) * }}}