From 14fde71643c50ada344c7579755f1a4329b94f34 Mon Sep 17 00:00:00 2001 From: Avasil Date: Fri, 11 May 2018 00:05:10 +0200 Subject: [PATCH 1/3] Add .parFlatTraverse and .parFlatSequence syntax --- core/src/main/scala/cats/syntax/parallel.scala | 16 ++++++++++++++++ .../test/scala/cats/tests/ParallelSuite.scala | 14 ++++++++++++++ .../src/test/scala/cats/tests/SyntaxSuite.scala | 9 +++++++++ 3 files changed, 39 insertions(+) diff --git a/core/src/main/scala/cats/syntax/parallel.scala b/core/src/main/scala/cats/syntax/parallel.scala index 62be5e7915..225e82e6e6 100644 --- a/core/src/main/scala/cats/syntax/parallel.scala +++ b/core/src/main/scala/cats/syntax/parallel.scala @@ -6,9 +6,15 @@ trait ParallelSyntax extends TupleParallelSyntax { implicit final def catsSyntaxParallelTraverse[T[_]: Traverse, A] (ta: T[A]): ParallelTraversableOps[T, A] = new ParallelTraversableOps[T, A](ta) + implicit final def catsSyntaxParallelTraverse[T[_]: Traverse: FlatMap, A] + (ta: T[A]): ParallelFlatTraversableOps[T, A] = new ParallelFlatTraversableOps[T, A](ta) + implicit final def catsSyntaxParallelSequence[T[_]: Traverse, M[_]: Monad, A] (tma: T[M[A]]): ParallelSequenceOps[T, M, A] = new ParallelSequenceOps[T, M, A](tma) + implicit final def catsSyntaxParallelFlatSequence[T[_]: Traverse: FlatMap, M[_]: Monad, A] + (tmta: T[M[T[A]]]): ParallelFlatSequenceOps[T, M, A] = new ParallelFlatSequenceOps[T, M, A](tmta) + implicit final def catsSyntaxParallelAp[M[_]: FlatMap, A](ma: M[A]): ParallelApOps[M, A] = new ParallelApOps[M, A](ma) } @@ -19,14 +25,24 @@ final class ParallelTraversableOps[T[_], A](val ta: T[A]) extends AnyVal { def parTraverse[M[_]: Monad, F[_], B] (f: A => M[B])(implicit T: Traverse[T], P: Parallel[M, F]): M[T[B]] = Parallel.parTraverse(ta)(f) +} +final class ParallelFlatTraversableOps[T[_], A](val ta: T[A]) extends AnyVal { + def parFlatTraverse[M[_]: Monad, F[_], B] + (f: A => M[T[B]])(implicit T0: Traverse[T], T1 : FlatMap[T], P: Parallel[M, F]): M[T[B]] = + Parallel.parFlatTraverse(ta)(f) } final class ParallelSequenceOps[T[_], M[_], A](val tma: T[M[A]]) extends AnyVal { def parSequence[F[_]] (implicit M: Monad[M], T: Traverse[T], P: Parallel[M, F]): M[T[A]] = Parallel.parSequence(tma) +} +final class ParallelFlatSequenceOps[T[_], M[_], A](val tmta: T[M[T[A]]]) extends AnyVal { + def parFlatSequence[F[_]] + (implicit M: Monad[M], T0: Traverse[T], T1 : FlatMap[T], P: Parallel[M, F]): M[T[A]] = + Parallel.parFlatSequence(tmta) } final class ParallelApOps[M[_], A](val ma: M[A]) extends AnyVal { diff --git a/tests/src/test/scala/cats/tests/ParallelSuite.scala b/tests/src/test/scala/cats/tests/ParallelSuite.scala index cf393fdd5a..f9b6434e93 100644 --- a/tests/src/test/scala/cats/tests/ParallelSuite.scala +++ b/tests/src/test/scala/cats/tests/ParallelSuite.scala @@ -79,6 +79,20 @@ class ParallelSuite extends CatsSuite with ApplicativeErrorForEitherTest { } } + test("ParFlatSequence syntax should be equivalent to Parallel.parFlatSequence") { + forAll { es: List[Either[String, List[Int]]] => + es.parFlatSequence should === (Parallel.parFlatSequence(es)) + } + } + + test("ParFlatTraverse syntax should be equivalent to Parallel.parFlatTraverse") { + forAll { es: List[Either[String, Int]] => + val f: Int => List[Int] = i => List(i, i + 1) + Parallel.parFlatTraverse(es)(e => e.map(f)) should + === (es.parFlatTraverse(e => e.map(f))) + } + } + test("ParNonEmptyFlatTraverse should be equivalent to parNonEmptyTraverse map flatten") { forAll { es: NonEmptyList[Either[String, Int]] => val f: Int => NonEmptyList[Int] = i => NonEmptyList.of(i, i + 1) diff --git a/tests/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/src/test/scala/cats/tests/SyntaxSuite.scala index 6bcd3b987b..880de18f7c 100644 --- a/tests/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/src/test/scala/cats/tests/SyntaxSuite.scala @@ -179,6 +179,15 @@ object SyntaxSuite extends AllInstances with AllSyntax { val ma2: M[A] = ma <& mb } + def testParallelFlat[M[_]: Monad, F[_], T[_]: Traverse: FlatMap, A, B](implicit P: Parallel[M, F]): Unit = { + val ta = mock[T[A]] + val f = mock[A => M[T[B]]] + val mtb = ta.parFlatTraverse(f) + + val tmta = mock[T[M[T[A]]]] + val mta = tmta.parFlatSequence + } + def testParallelTuple[M[_]: Monad, F[_], A, B, C, Z](implicit P: NonEmptyParallel[M, F]) = { val tfabc = mock[(M[A], M[B], M[C])] val fa = mock[M[A]] From 3bf85136bd40f95c049a36ef1525e65e8869d61b Mon Sep 17 00:00:00 2001 From: Avasil Date: Fri, 11 May 2018 00:10:50 +0200 Subject: [PATCH 2/3] Fix typo in catsSyntaxParallelFlatTraverse --- core/src/main/scala/cats/syntax/parallel.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/syntax/parallel.scala b/core/src/main/scala/cats/syntax/parallel.scala index 225e82e6e6..b3393d6c6a 100644 --- a/core/src/main/scala/cats/syntax/parallel.scala +++ b/core/src/main/scala/cats/syntax/parallel.scala @@ -6,7 +6,7 @@ trait ParallelSyntax extends TupleParallelSyntax { implicit final def catsSyntaxParallelTraverse[T[_]: Traverse, A] (ta: T[A]): ParallelTraversableOps[T, A] = new ParallelTraversableOps[T, A](ta) - implicit final def catsSyntaxParallelTraverse[T[_]: Traverse: FlatMap, A] + implicit final def catsSyntaxParallelFlatTraverse[T[_]: Traverse: FlatMap, A] (ta: T[A]): ParallelFlatTraversableOps[T, A] = new ParallelFlatTraversableOps[T, A](ta) implicit final def catsSyntaxParallelSequence[T[_]: Traverse, M[_]: Monad, A] From 3fcf16f5f3f30d1ec834a688f1a29087b101a2c5 Mon Sep 17 00:00:00 2001 From: Avasil Date: Fri, 11 May 2018 07:46:35 +0200 Subject: [PATCH 3/3] Binary compability --- core/src/main/scala/cats/syntax/all.scala | 2 +- core/src/main/scala/cats/syntax/parallel.scala | 13 +++++++------ tests/src/test/scala/cats/tests/SyntaxSuite.scala | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/core/src/main/scala/cats/syntax/all.scala b/core/src/main/scala/cats/syntax/all.scala index dec09ed8e0..ccfe71a1d0 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -59,4 +59,4 @@ trait AllSyntaxBinCompat0 with ApplicativeErrorExtension with TrySyntax -trait AllSyntaxBinCompat1 extends FlatMapOptionSyntax +trait AllSyntaxBinCompat1 extends FlatMapOptionSyntax with ParallelFlatSyntax diff --git a/core/src/main/scala/cats/syntax/parallel.scala b/core/src/main/scala/cats/syntax/parallel.scala index b3393d6c6a..02b6bf8e70 100644 --- a/core/src/main/scala/cats/syntax/parallel.scala +++ b/core/src/main/scala/cats/syntax/parallel.scala @@ -6,19 +6,20 @@ trait ParallelSyntax extends TupleParallelSyntax { implicit final def catsSyntaxParallelTraverse[T[_]: Traverse, A] (ta: T[A]): ParallelTraversableOps[T, A] = new ParallelTraversableOps[T, A](ta) - implicit final def catsSyntaxParallelFlatTraverse[T[_]: Traverse: FlatMap, A] - (ta: T[A]): ParallelFlatTraversableOps[T, A] = new ParallelFlatTraversableOps[T, A](ta) - implicit final def catsSyntaxParallelSequence[T[_]: Traverse, M[_]: Monad, A] (tma: T[M[A]]): ParallelSequenceOps[T, M, A] = new ParallelSequenceOps[T, M, A](tma) - implicit final def catsSyntaxParallelFlatSequence[T[_]: Traverse: FlatMap, M[_]: Monad, A] - (tmta: T[M[T[A]]]): ParallelFlatSequenceOps[T, M, A] = new ParallelFlatSequenceOps[T, M, A](tmta) - implicit final def catsSyntaxParallelAp[M[_]: FlatMap, A](ma: M[A]): ParallelApOps[M, A] = new ParallelApOps[M, A](ma) } +trait ParallelFlatSyntax { + implicit final def catsSyntaxParallelFlatTraverse[T[_]: Traverse: FlatMap, A] + (ta: T[A]): ParallelFlatTraversableOps[T, A] = new ParallelFlatTraversableOps[T, A](ta) + + implicit final def catsSyntaxParallelFlatSequence[T[_]: Traverse: FlatMap, M[_]: Monad, A] + (tmta: T[M[T[A]]]): ParallelFlatSequenceOps[T, M, A] = new ParallelFlatSequenceOps[T, M, A](tmta) +} final class ParallelTraversableOps[T[_], A](val ta: T[A]) extends AnyVal { diff --git a/tests/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/src/test/scala/cats/tests/SyntaxSuite.scala index 880de18f7c..3670448056 100644 --- a/tests/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/src/test/scala/cats/tests/SyntaxSuite.scala @@ -3,7 +3,7 @@ package tests import cats.arrow.Compose import cats.instances.AllInstances -import cats.syntax.AllSyntax +import cats.syntax.{AllSyntax, AllSyntaxBinCompat1} /** @@ -24,7 +24,7 @@ import cats.syntax.AllSyntax * * None of these tests should ever run, or do any runtime checks. */ -object SyntaxSuite extends AllInstances with AllSyntax { +object SyntaxSuite extends AllInstances with AllSyntax with AllSyntaxBinCompat1 { // pretend we have a value of type A def mock[A]: A = ???