diff --git a/core/src/main/scala/cats/syntax/parallel.scala b/core/src/main/scala/cats/syntax/parallel.scala index 8fa55c75f1..4fd585cb1e 100644 --- a/core/src/main/scala/cats/syntax/parallel.scala +++ b/core/src/main/scala/cats/syntax/parallel.scala @@ -53,13 +53,24 @@ trait ParallelSyntax extends TupleParallelSyntax { implicit final def catsSyntaxParallelSequence1[T[_]: Traverse, M[_], A](tma: T[M[A]]): ParallelSequenceOps1[T, M, A] = new ParallelSequenceOps1(tma) - implicit final def catsSyntaxParallelAp[M[_]: FlatMap, A](ma: M[A]): ParallelApOps[M, A] = + @deprecated("Kept for binary compatibility", "2.8.0") + final def catsSyntaxParallelAp[M[_]: FlatMap, A](ma: M[A]): ParallelApOps[M, A] = new ParallelApOps(ma) + + implicit final def catsSyntaxParallelAp1[M[_], A](ma: M[A]): ParallelApOps1[M, A] = + new ParallelApOps1(ma) + + implicit final def catsSyntaxNonEmptyParallelAp[M[_], A](ma: M[A]): NonEmptyParallelApOps[M, A] = + new NonEmptyParallelApOps(ma) } trait ParallelApplySyntax { - implicit final def catsSyntaxParallelApply[F[_], A, B](fa: F[A => B]): ParallelApplyOps[F, A, B] = + @deprecated("Kept for binary compatibility", "2.8.0") + final def catsSyntaxParallelApply[F[_], A, B](fa: F[A => B]): ParallelApplyOps[F, A, B] = new ParallelApplyOps(fa) + + implicit final def catsSyntaxNonEmptyParallelApply[F[_], A, B](fa: F[A => B]): NonEmptyParallelApplyOps[F, A, B] = + new NonEmptyParallelApplyOps(fa) } trait ParallelFlatSyntax { @@ -258,8 +269,8 @@ final class ParallelUnorderedFlatSequenceOps[T[_], M[_], A](private val tmta: T[ Parallel.parUnorderedFlatSequence(tmta) } +@deprecated("Kept for binary compatibility", "2.8.0") final class ParallelApOps[M[_], A](private val ma: M[A]) extends AnyVal { - def &>[B](mb: M[B])(implicit P: Parallel[M]): M[B] = P.parProductR(ma)(mb) @@ -279,6 +290,29 @@ final class ParallelApOps[M[_], A](private val ma: M[A]) extends AnyVal { Parallel.parReplicateA(n, ma) } +final class ParallelApOps1[M[_], A](private val ma: M[A]) extends AnyVal { + def parReplicateA(n: Int)(implicit P: Parallel[M]): M[List[A]] = + Parallel.parReplicateA(n, ma) +} + +final class NonEmptyParallelApOps[M[_], A](private val ma: M[A]) extends AnyVal { + def &>[B](mb: M[B])(implicit P: NonEmptyParallel[M]): M[B] = + P.parProductR[A, B](ma)(mb) + + def <&[B](mb: M[B])(implicit P: NonEmptyParallel[M]): M[A] = + P.parProductL[A, B](ma)(mb) + + def parProductL[B](mb: M[B])(implicit P: NonEmptyParallel[M]): M[A] = + P.parProductL[A, B](ma)(mb) + + def parProductR[B](mb: M[B])(implicit P: NonEmptyParallel[M]): M[B] = + P.parProductR[A, B](ma)(mb) + + def parProduct[B](mb: M[B])(implicit P: NonEmptyParallel[M]): M[(A, B)] = + Parallel.parProduct(ma, mb) +} + +@deprecated("Kept for binary compatibility", "2.8.0") final class ParallelApplyOps[M[_], A, B](private val mab: M[A => B]) extends AnyVal { def <&>(ma: M[A])(implicit P: Parallel[M]): M[B] = Parallel.parAp(mab)(ma)(P) @@ -287,6 +321,14 @@ final class ParallelApplyOps[M[_], A, B](private val mab: M[A => B]) extends Any Parallel.parAp(mab)(ma) } +final class NonEmptyParallelApplyOps[M[_], A, B](private val mab: M[A => B]) extends AnyVal { + def <&>(ma: M[A])(implicit P: NonEmptyParallel[M]): M[B] = + Parallel.parAp[M, A, B](mab)(ma)(P) + + def parAp(ma: M[A])(implicit P: NonEmptyParallel[M]): M[B] = + Parallel.parAp[M, A, B](mab)(ma) +} + final class ParallelBitraverseOps[T[_, _], A, B](private val tab: T[A, B]) extends AnyVal { def parBitraverse[M[_], C, D](f: A => M[C], g: B => M[D])(implicit T: Bitraverse[T], P: Parallel[M]): M[T[C, D]] = Parallel.parBitraverse(tab)(f, g) diff --git a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala index 66c2fb9738..9bb2c7004b 100644 --- a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala @@ -184,7 +184,7 @@ object SyntaxSuite { val gunit: G[F[A]] = fga.nonEmptySequence } - def testParallel[M[_]: Monad, F[_], T[_]: Traverse, A, B](implicit P: Parallel.Aux[M, F]): Unit = { + def testParallel[M[_]: Parallel, T[_]: Traverse, A, B]: Unit = { val ta = mock[T[A]] val f = mock[A => M[B]] val mtb = ta.parTraverse(f) @@ -192,6 +192,12 @@ object SyntaxSuite { val tma = mock[T[M[A]]] val mta = tma.parSequence + val ma = mock[M[A]] + + val mla: M[List[A]] = ma.parReplicateA(mock[Int]) + } + + def testNonEmptyParallel[M[_]: NonEmptyParallel, A, B]: Unit = { val ma = mock[M[A]] val mb = mock[M[B]] @@ -205,7 +211,6 @@ object SyntaxSuite { val mb4: M[B] = ma.parProductR(mb) val mab2: M[(A, B)] = ma.parProduct(mb) val mb5: M[B] = mab.parAp(ma) - val mla: M[List[A]] = ma.parReplicateA(mock[Int]) } def testParallelUnorderedTraverse[M[_]: Monad, F[_]: CommutativeApplicative, T[_]: UnorderedTraverse: FlatMap, A, B](