Skip to content

Commit

Permalink
Infer dependent parameter in NonEmpty/ParallelTests/Laws
Browse files Browse the repository at this point in the history
  • Loading branch information
djspiewak committed Sep 9, 2019
1 parent b625536 commit 3efcda1
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 55 deletions.
14 changes: 10 additions & 4 deletions laws/src/main/scala/cats/laws/NonEmptyParallelLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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] =
Aux[M, ev.F](ev)

def Aux[M[_], F[_]](implicit ev: NonEmptyParallel.Aux[M, F]): NonEmptyParallelLaws.Aux[M, F] =
new NonEmptyParallelLaws[M] { val P: ev.type = ev }
}
13 changes: 9 additions & 4 deletions laws/src/main/scala/cats/laws/ParallelLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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] =
Aux[M, ev.F](ev)

def Aux[M[_], F[_]](implicit ev: Parallel.Aux[M, F]): ParallelLaws.Aux[M, F] =
new ParallelLaws[M] { val P: ev.type = ev }
}
Original file line number Diff line number Diff line change
Expand Up @@ -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]],
Expand All @@ -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] =
Aux[M, ev.F](ev)

def Aux[M[_], F[_]](implicit ev: NonEmptyParallel.Aux[M, F]): NonEmptyParallelTests.Aux[M, F] =
new NonEmptyParallelTests[M] { val laws = NonEmptyParallelLaws[M] }
}
13 changes: 9 additions & 4 deletions laws/src/main/scala/cats/laws/discipline/ParallelTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]],
Expand All @@ -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] =
Aux[M, ev.F](ev)

def Aux[M[_], F[_]](implicit ev: Parallel.Aux[M, F]): ParallelTests.Aux[M, F] =
new ParallelTests[M] { val laws = ParallelLaws[M] }
}
10 changes: 5 additions & 5 deletions tests/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala
Original file line number Diff line number Diff line change
@@ -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._
Expand Down Expand Up @@ -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 =>
Expand Down
59 changes: 25 additions & 34 deletions tests/src/test/scala/cats/tests/ParallelSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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.Aux[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]
)
}
Expand Down

0 comments on commit 3efcda1

Please sign in to comment.