diff --git a/laws/src/main/scala/cats/laws/NonEmptyParallelLaws.scala b/laws/src/main/scala/cats/laws/NonEmptyParallelLaws.scala index 96deeb8df0..880b3ba1d9 100644 --- a/laws/src/main/scala/cats/laws/NonEmptyParallelLaws.scala +++ b/laws/src/main/scala/cats/laws/NonEmptyParallelLaws.scala @@ -4,8 +4,9 @@ package laws /** * Laws that must be obeyed by any `cats.NonEmptyParallel`. */ -trait NonEmptyParallelLaws[M[_], F[_]] { - def P: NonEmptyParallel.Aux[M, F] +trait NonEmptyParallelLaws[M[_]] { + val P: NonEmptyParallel[M] + type F[A] = P.F[A] def parallelRoundTrip[A](ma: M[A]): IsEq[M[A]] = P.sequential(P.parallel(ma)) <-> ma @@ -18,6 +19,11 @@ trait NonEmptyParallelLaws[M[_], F[_]] { } object NonEmptyParallelLaws { - def apply[M[_], F[_]](implicit ev: NonEmptyParallel.Aux[M, F]): NonEmptyParallelLaws[M, F] = - new NonEmptyParallelLaws[M, F] { def P: NonEmptyParallel.Aux[M, F] = ev } + type Aux[M[_], F0[_]] = NonEmptyParallelLaws[M] { type F[A] = F0[A]; val P: NonEmptyParallel.Aux[M, F0] } + + def apply[M[_]](implicit ev: NonEmptyParallel[M]): NonEmptyParallelLaws.Aux[M, ev.F] = + apply[M, ev.F](ev, implicitly) + + def apply[M[_], F[_]](implicit ev: NonEmptyParallel.Aux[M, F], D: DummyImplicit): NonEmptyParallelLaws.Aux[M, F] = + new NonEmptyParallelLaws[M] { val P: ev.type = ev } } diff --git a/laws/src/main/scala/cats/laws/ParallelLaws.scala b/laws/src/main/scala/cats/laws/ParallelLaws.scala index 892ca79eae..4e7165e94a 100644 --- a/laws/src/main/scala/cats/laws/ParallelLaws.scala +++ b/laws/src/main/scala/cats/laws/ParallelLaws.scala @@ -4,14 +4,19 @@ package laws /** * Laws that must be obeyed by any `cats.Parallel`. */ -trait ParallelLaws[M[_], F[_]] extends NonEmptyParallelLaws[M, F] { - def P: Parallel.Aux[M, F] +trait ParallelLaws[M[_]] extends NonEmptyParallelLaws[M] { + val P: Parallel[M] def isomorphicPure[A](a: A): IsEq[F[A]] = P.applicative.pure(a) <-> P.parallel(P.monad.pure(a)) } object ParallelLaws { - def apply[M[_], F[_]](implicit ev: Parallel.Aux[M, F]): ParallelLaws[M, F] = - new ParallelLaws[M, F] { def P: Parallel.Aux[M, F] = ev } + type Aux[M[_], F0[_]] = ParallelLaws[M] { type F[A] = F0[A]; val P: Parallel.Aux[M, F0] } + + def apply[M[_]](implicit ev: Parallel[M]): ParallelLaws.Aux[M, ev.F] = + apply[M, ev.F](ev, implicitly) + + def apply[M[_], F[_]](implicit ev: Parallel.Aux[M, F], D: DummyImplicit): ParallelLaws.Aux[M, F] = + new ParallelLaws[M] { val P: ev.type = ev } } diff --git a/laws/src/main/scala/cats/laws/discipline/NonEmptyParallelTests.scala b/laws/src/main/scala/cats/laws/discipline/NonEmptyParallelTests.scala index 64b14b8c3f..b503b3329b 100644 --- a/laws/src/main/scala/cats/laws/discipline/NonEmptyParallelTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/NonEmptyParallelTests.scala @@ -6,8 +6,9 @@ import org.scalacheck.Arbitrary import org.scalacheck.Prop.forAll import org.typelevel.discipline.Laws -trait NonEmptyParallelTests[M[_], F[_]] extends Laws { - def laws: NonEmptyParallelLaws[M, F] +trait NonEmptyParallelTests[M[_]] extends Laws { + val laws: NonEmptyParallelLaws[M] + type F[A] = laws.F[A] def nonEmptyParallel[A, B](implicit ArbA: Arbitrary[A], ArbM: Arbitrary[M[A]], @@ -27,6 +28,11 @@ trait NonEmptyParallelTests[M[_], F[_]] extends Laws { } object NonEmptyParallelTests { - def apply[M[_], F[_]](implicit ev: NonEmptyParallel.Aux[M, F]): NonEmptyParallelTests[M, F] = - new NonEmptyParallelTests[M, F] { val laws: NonEmptyParallelLaws[M, F] = NonEmptyParallelLaws[M, F] } + type Aux[M[_], F0[_]] = NonEmptyParallelTests[M] { type F[A] = F0[A]; val laws: NonEmptyParallelLaws.Aux[M, F0] } + + def apply[M[_]](implicit ev: NonEmptyParallel[M]): NonEmptyParallelTests.Aux[M, ev.F] = + apply[M, ev.F](ev, implicitly) + + def apply[M[_], F[_]](implicit ev: NonEmptyParallel.Aux[M, F], D: DummyImplicit): NonEmptyParallelTests.Aux[M, F] = + new NonEmptyParallelTests[M] { val laws = NonEmptyParallelLaws[M] } } diff --git a/laws/src/main/scala/cats/laws/discipline/ParallelTests.scala b/laws/src/main/scala/cats/laws/discipline/ParallelTests.scala index b5b394adc7..5f4e28fa87 100644 --- a/laws/src/main/scala/cats/laws/discipline/ParallelTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/ParallelTests.scala @@ -5,8 +5,8 @@ package discipline import org.scalacheck.Arbitrary import org.scalacheck.Prop.forAll -trait ParallelTests[M[_], F[_]] extends NonEmptyParallelTests[M, F] { - def laws: ParallelLaws[M, F] +trait ParallelTests[M[_]] extends NonEmptyParallelTests[M] { + val laws: ParallelLaws[M] def parallel[A, B](implicit ArbA: Arbitrary[A], ArbM: Arbitrary[M[A]], @@ -24,6 +24,11 @@ trait ParallelTests[M[_], F[_]] extends NonEmptyParallelTests[M, F] { } object ParallelTests { - def apply[M[_], F[_]](implicit ev: Parallel.Aux[M, F]): ParallelTests[M, F] = - new ParallelTests[M, F] { val laws: ParallelLaws[M, F] = ParallelLaws[M, F] } + type Aux[M[_], F0[_]] = ParallelTests[M] { type F[A] = F0[A]; val laws: ParallelLaws.Aux[M, F0] } + + def apply[M[_]](implicit ev: Parallel[M]): ParallelTests.Aux[M, ev.F] = + apply[M, ev.F](ev, implicitly) + + def apply[M[_], F[_]](implicit ev: Parallel.Aux[M, F], D: DummyImplicit): ParallelTests.Aux[M, F] = + new ParallelTests[M] { val laws = ParallelLaws[M] } } diff --git a/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala b/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala index cfc4ce7437..43c3230dd9 100644 --- a/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala +++ b/tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala @@ -1,7 +1,7 @@ package cats package tests -import cats.data.{NonEmptyLazyList, OneAnd, ZipLazyList} +import cats.data.NonEmptyLazyList import cats.instances.lazyList._ import cats.laws.discipline.{NonEmptyParallelTests, ParallelTests} import cats.laws.discipline.arbitrary._ @@ -123,11 +123,11 @@ trait ScalaVersionSpecificParallelSuite { self: ParallelSuite => } // Can't test Parallel here, as Applicative[ZipLazyList].pure doesn't terminate - checkAll("Parallel[LazyList, ZipLazyList]", - NonEmptyParallelTests[LazyList, ZipLazyList].nonEmptyParallel[Int, String]) + checkAll("Parallel[LazyList]", + NonEmptyParallelTests[LazyList].nonEmptyParallel[Int, String]) - checkAll("Parallel[NonEmptyLazyList, OneAnd[ZipLazyList, *]]", - ParallelTests[NonEmptyLazyList, OneAnd[ZipLazyList, *]].parallel[Int, String]) + checkAll("Parallel[NonEmptyLazyList]", + ParallelTests[NonEmptyLazyList].parallel[Int, String]) } trait ScalaVersionSpecificRegressionSuite { self: RegressionSuite => diff --git a/tests/src/test/scala/cats/tests/ParallelSuite.scala b/tests/src/test/scala/cats/tests/ParallelSuite.scala index 4f385de2c2..d1b4168aac 100644 --- a/tests/src/test/scala/cats/tests/ParallelSuite.scala +++ b/tests/src/test/scala/cats/tests/ParallelSuite.scala @@ -3,7 +3,6 @@ package tests import cats._ import cats.data.NonEmptyList.ZipNonEmptyList -import cats.data.NonEmptyVector.ZipNonEmptyVector import cats.data._ import org.scalatest.funsuite.AnyFunSuiteLike import cats.laws.discipline.{ApplicativeErrorTests, MiniInt, NonEmptyParallelTests, ParallelTests, SerializableTests} @@ -416,63 +415,55 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest with Sc resultWithInstance should ===("parallel".some) } - checkAll("Parallel[Either[String, *], Validated[String, *]]", - ParallelTests[Either[String, *], Validated[String, *]].parallel[Int, String]) - checkAll("Parallel[Ior[String, *], Ior[String, *]]", - ParallelTests[Ior[String, *], Ior[String, *]].parallel[Int, String]) + checkAll("Parallel[Either[String, *]", ParallelTests[Either[String, *]].parallel[Int, String]) + checkAll("Parallel[Ior[String, *]]", ParallelTests[Ior[String, *]].parallel[Int, String]) checkAll( - "Parallel[IorT[F, String, *], IorT[F, String, *]] with parallel effect", - ParallelTests[IorT[Either[String, *], String, *], IorT[Validated[String, *], String, *]].parallel[Int, String] + "Parallel[IorT[F, String, *]] with parallel effect", + ParallelTests[IorT[Either[String, *], String, *]].parallel[Int, String] ) checkAll( - "Parallel[IorT[F, String, *], IorT[F, String, *]] with sequential effect", - ParallelTests[IorT[Option, String, *], IorT[Option, String, *]].parallel[Int, String] + "Parallel[IorT[F, String, *]] with sequential effect", + ParallelTests[IorT[Option, String, *]].parallel[Int, String] ) - checkAll("Parallel[OptionT[M, *], Nested[F, Option, *]]", - ParallelTests[OptionT[Either[String, *], *], Nested[Validated[String, *], Option, *]].parallel[Int, String]) + checkAll("Parallel[OptionT[M, *]]", ParallelTests[OptionT[Either[String, *], *]].parallel[Int, String]) checkAll( - "Parallel[EitherT[M, String, *], Nested[F, Validated[String, *], *]]", - ParallelTests[EitherT[Either[String, *], String, *], Nested[Validated[String, *], Validated[String, *], *]] + "Parallel[EitherT[M, String, *]]", + ParallelTests[EitherT[Either[String, *], String, *]] .parallel[Int, String] ) checkAll( - "Parallel[EitherT[Option, String, *], Nested[Option, Validated[String, *], *]]", - ParallelTests[EitherT[Option, String, *], Nested[Option, Validated[String, *], *]].parallel[Int, String] + "Parallel[EitherT[Option, String, *]]", + ParallelTests[EitherT[Option, String, *]].parallel[Int, String] ) checkAll( - "Parallel[WriterT[M, Int, *], WriterT[F, Int, *]]", - ParallelTests[WriterT[Either[String, *], Int, *], WriterT[Validated[String, *], Int, *]].parallel[Int, String] + "Parallel[WriterT[M, Int, *]]", + ParallelTests[WriterT[Either[String, *], Int, *]].parallel[Int, String] ) - checkAll("NonEmptyParallel[Vector, ZipVector]", - NonEmptyParallelTests[Vector, ZipVector].nonEmptyParallel[Int, String]) - checkAll("NonEmptyParallel[List, ZipList]", NonEmptyParallelTests[List, ZipList].nonEmptyParallel[Int, String]) + checkAll("NonEmptyParallel[Vector]", NonEmptyParallelTests[Vector].nonEmptyParallel[Int, String]) + checkAll("NonEmptyParallel[List]", NonEmptyParallelTests[List].nonEmptyParallel[Int, String]) // Can't test Parallel here, as Applicative[ZipStream].pure doesn't terminate - checkAll("Parallel[Stream, ZipStream]", NonEmptyParallelTests[Stream, ZipStream].nonEmptyParallel[Int, String]) + checkAll("Parallel[Stream]", NonEmptyParallelTests[Stream].nonEmptyParallel[Int, String]) - checkAll("NonEmptyParallel[NonEmptyVector, ZipNonEmptyVector]", - NonEmptyParallelTests[NonEmptyVector, ZipNonEmptyVector].nonEmptyParallel[Int, String]) + checkAll("NonEmptyParallel[NonEmptyVector]", NonEmptyParallelTests[NonEmptyVector].nonEmptyParallel[Int, String]) - checkAll("NonEmptyParallel[NonEmptyList, ZipNonEmptyList]", - NonEmptyParallelTests[NonEmptyList, ZipNonEmptyList].nonEmptyParallel[Int, String]) + checkAll("NonEmptyParallel[NonEmptyList]", NonEmptyParallelTests[NonEmptyList].nonEmptyParallel[Int, String]) - checkAll("Parallel[NonEmptyStream, OneAnd[ZipStream, *]", - ParallelTests[NonEmptyStream, OneAnd[ZipStream, *]].parallel[Int, String]) + // TODO this doesn't infer? + checkAll("Parallel[NonEmptyStream]", ParallelTests[NonEmptyStream, OneAnd[ZipStream, *]].parallel[Int, String]) - checkAll("Parallel[Id, Id]", ParallelTests[Id, Id].parallel[Int, String]) + checkAll("Parallel[Id]", ParallelTests[Id].parallel[Int, String]) - checkAll("NonEmptyParallel[NonEmptyList, ZipNonEmptyList]", - SerializableTests.serializable(NonEmptyParallel[NonEmptyList, ZipNonEmptyList])) + checkAll("NonEmptyParallel[NonEmptyList]", SerializableTests.serializable(NonEmptyParallel[NonEmptyList])) - checkAll("Parallel[Either[String, *], Validated[String, *]]", - SerializableTests.serializable(Parallel[Either[String, *], Validated[String, *]])) + checkAll("Parallel[Either[String, *]]", SerializableTests.serializable(Parallel[Either[String, *]])) { implicit def kleisliEq[F[_], A, B](implicit ev: Eq[A => F[B]]): Eq[Kleisli[F, A, B]] = Eq.by[Kleisli[F, A, B], A => F[B]](_.run) checkAll( - "Parallel[KleisliT[M, A, *], Kleisli[F, A, *]]", - ParallelTests[Kleisli[Either[String, *], MiniInt, *], Kleisli[Validated[String, *], MiniInt, *]] + "Parallel[KleisliT[M, A, *]]", + ParallelTests[Kleisli[Either[String, *], MiniInt, *]] .parallel[Int, String] ) }