From abd54ff91c00460673c0ac98a35346be62524a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Gawry=C5=9B?= Date: Thu, 24 May 2018 01:36:19 +0200 Subject: [PATCH] Add .parFlatTraverse and .parFlatSequence syntax (#2256) * Add .parFlatTraverse and .parFlatSequence syntax * Fix typo in catsSyntaxParallelFlatTraverse * Binary compability --- core/src/main/scala/cats/syntax/all.scala | 3 ++- core/src/main/scala/cats/syntax/parallel.scala | 17 +++++++++++++++++ .../test/scala/cats/tests/ParallelSuite.scala | 14 ++++++++++++++ .../src/test/scala/cats/tests/SyntaxSuite.scala | 9 +++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/syntax/all.scala b/core/src/main/scala/cats/syntax/all.scala index 87c2497f04..9dd4f81989 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -60,5 +60,6 @@ trait AllSyntaxBinCompat0 with TrySyntax trait AllSyntaxBinCompat1 - extends FlatMapOptionSyntax + extends FlatMapOptionSyntax with NestedSyntax + with ParallelFlatSyntax diff --git a/core/src/main/scala/cats/syntax/parallel.scala b/core/src/main/scala/cats/syntax/parallel.scala index 62be5e7915..02b6bf8e70 100644 --- a/core/src/main/scala/cats/syntax/parallel.scala +++ b/core/src/main/scala/cats/syntax/parallel.scala @@ -13,20 +13,37 @@ trait ParallelSyntax extends TupleParallelSyntax { 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 { 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 5dc48aa6c0..8da279c4fe 100644 --- a/tests/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/src/test/scala/cats/tests/SyntaxSuite.scala @@ -180,6 +180,15 @@ object SyntaxSuite extends AllInstances with AllSyntax with AllSyntaxBinCompat1 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]]