From 08d046c783e7a430fa0a9bcac08b603f815c8d66 Mon Sep 17 00:00:00 2001 From: Matthias Berndt Date: Sun, 14 Jul 2019 04:25:44 +0200 Subject: [PATCH 1/3] add unordered parallel variants of (flat)traverse and (flat)sequence --- core/src/main/scala/cats/Parallel.scala | 20 +++++++ core/src/main/scala/cats/syntax/all.scala | 3 ++ core/src/main/scala/cats/syntax/package.scala | 1 + .../src/main/scala/cats/syntax/parallel.scala | 52 ++++++++++++++++++- 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/Parallel.scala b/core/src/main/scala/cats/Parallel.scala index 2f905da39d..466b172f81 100644 --- a/core/src/main/scala/cats/Parallel.scala +++ b/core/src/main/scala/cats/Parallel.scala @@ -169,6 +169,26 @@ object Parallel extends ParallelArityFunctions2 { P.sequential(gtb) } + def parUnorderedTraverse[T[_]: UnorderedTraverse, M[_], F[_]: CommutativeApplicative, A, B]( + ta: T[A] + )(f: A => M[B])(implicit P: Parallel[M, F]): M[T[B]] = + P.sequential(UnorderedTraverse[T].unorderedTraverse(ta)(a => P.parallel(f(a)))) + + def parUnorderedSequence[T[_]: UnorderedTraverse, M[_], F[_]: CommutativeApplicative, A]( + ta: T[M[A]] + )(implicit P: Parallel[M, F]): M[T[A]] = + parUnorderedTraverse[T, M, F, M[A], A](ta)(Predef.identity) + + def parUnorderedFlatTraverse[T[_]: UnorderedTraverse: FlatMap, M[_], F[_]: CommutativeApplicative, A, B]( + ta: T[A] + )(f: A => M[T[B]])(implicit P: Parallel[M, F]): M[T[B]] = + P.monad.map(parUnorderedTraverse[T, M, F, A, T[B]](ta)(f))(FlatMap[T].flatten) + + def parUnorderedFlatSequence[T[_]: UnorderedTraverse: FlatMap, M[_], F[_]: CommutativeApplicative, A]( + ta: T[M[T[A]]] + )(implicit P: Parallel[M, F]): M[T[A]] = + parUnorderedFlatTraverse[T, M, F, M[T[A]], A](ta)(Predef.identity) + /** * Like `NonEmptyTraverse[A].nonEmptySequence`, but uses the apply instance * corresponding to the Parallel instance instead. diff --git a/core/src/main/scala/cats/syntax/all.scala b/core/src/main/scala/cats/syntax/all.scala index a12639f1b9..2b19d210e9 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -9,6 +9,7 @@ abstract class AllSyntaxBinCompat with AllSyntaxBinCompat3 with AllSyntaxBinCompat4 with AllSyntaxBinCompat5 + with AllSyntaxBinCompat6 trait AllSyntax extends AlternativeSyntax @@ -90,3 +91,5 @@ trait AllSyntaxBinCompat4 with BitraverseSyntaxBinCompat0 trait AllSyntaxBinCompat5 extends ParallelBitraverseSyntax + +trait AllSyntaxBinCompat6 extends ParallelUnorderedTraverseSyntax diff --git a/core/src/main/scala/cats/syntax/package.scala b/core/src/main/scala/cats/syntax/package.scala index f7f4170aad..a6aa644a67 100644 --- a/core/src/main/scala/cats/syntax/package.scala +++ b/core/src/main/scala/cats/syntax/package.scala @@ -45,6 +45,7 @@ package object syntax { with ParallelFlatSyntax with ParallelApplySyntax with ParallelBitraverseSyntax + with ParallelUnorderedTraverseSyntax object partialOrder extends PartialOrderSyntax object profunctor extends ProfunctorSyntax object reducible extends ReducibleSyntax with ReducibleSyntaxBinCompat0 diff --git a/core/src/main/scala/cats/syntax/parallel.scala b/core/src/main/scala/cats/syntax/parallel.scala index 79bd2ed696..6059f365a8 100644 --- a/core/src/main/scala/cats/syntax/parallel.scala +++ b/core/src/main/scala/cats/syntax/parallel.scala @@ -1,6 +1,6 @@ package cats.syntax -import cats.{Bitraverse, FlatMap, Foldable, Monad, Parallel, Traverse} +import cats.{Bitraverse, CommutativeApplicative, FlatMap, Foldable, Monad, Parallel, Traverse, UnorderedTraverse} trait ParallelSyntax extends TupleParallelSyntax { @@ -61,6 +61,29 @@ trait ParallelBitraverseSyntax { new ParallelLeftSequenceOps[T, M, A, B](tmab) } +trait ParallelUnorderedTraverseSyntax { + implicit final def catsSyntaxParallelUnorderedTraverse[T[_], A]( + ta: T[A] + ): ParallelUnorderedTraverseOps[T, A] = + new ParallelUnorderedTraverseOps[T, A](ta) + + implicit final def catsSyntaxParallelUnorderedSequence[T[_], M[_], A]( + tma: T[M[A]] + ): ParallelUnorderedSequenceOps[T, M, A] = + new ParallelUnorderedSequenceOps[T, M, A](tma) + + implicit final def catsSyntaxParallelUnorderedFlatTraverse[T[_], A]( + ta: T[A] + ): ParallelUnorderedFlatTraverseOps[T, A] = + new ParallelUnorderedFlatTraverseOps[T, A](ta) + + implicit final def catsSyntaxParallelUnorderedFlatSequence[T[_], M[_], A]( + tmta: T[M[T[A]]] + ): ParallelUnorderedFlatSequenceOps[T, M, A] = + new ParallelUnorderedFlatSequenceOps[T, M, A](tmta) + +} + final class ParallelTraversableOps[T[_], A](private 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) @@ -94,6 +117,33 @@ final class ParallelFlatSequenceOps[T[_], M[_], A](private val tmta: T[M[T[A]]]) Parallel.parFlatSequence(tmta) } +final class ParallelUnorderedSequenceOps[T[_], M[_], A](private val tmta: T[M[A]]) extends AnyVal { + def parUnorderedFlatSequence[F[_]: CommutativeApplicative](implicit P: Parallel[M, F], + Tutraverse: UnorderedTraverse[T]): M[T[A]] = + Parallel.parUnorderedSequence(tmta) +} + +final class ParallelUnorderedTraverseOps[T[_], A](private val ta: T[A]) extends AnyVal { + def parUnorderedFlatTraverse[M[_], F[_]: CommutativeApplicative, B]( + f: A => M[B] + )(implicit P: Parallel[M, F], Tutraverse: UnorderedTraverse[T]): M[T[B]] = + Parallel.parUnorderedTraverse(ta)(f) +} + +final class ParallelUnorderedFlatSequenceOps[T[_], M[_], A](private val tmta: T[M[T[A]]]) extends AnyVal { + def parUnorderedFlatSequence[F[_]: CommutativeApplicative](implicit P: Parallel[M, F], + Tflatmap: FlatMap[T], + Tutraverse: UnorderedTraverse[T]): M[T[A]] = + Parallel.parUnorderedFlatSequence(tmta) +} + +final class ParallelUnorderedFlatTraverseOps[T[_], A](private val ta: T[A]) extends AnyVal { + def parUnorderedFlatTraverse[M[_], F[_]: CommutativeApplicative, B]( + f: A => M[T[B]] + )(implicit P: Parallel[M, F], Tflatmap: FlatMap[T], Tutraverse: UnorderedTraverse[T]): M[T[B]] = + Parallel.parUnorderedFlatTraverse(ta)(f) +} + final class ParallelApOps[M[_], A](private val ma: M[A]) extends AnyVal { def &>[F[_], B](mb: M[B])(implicit P: Parallel[M, F]): M[B] = From c00f6f9b849c273bd954e4fa76310985b9176b1f Mon Sep 17 00:00:00 2001 From: Matthias Berndt Date: Sat, 3 Aug 2019 00:40:04 +0200 Subject: [PATCH 2/3] add some tests and fix some bugs --- .../src/main/scala/cats/syntax/parallel.scala | 23 +++++++++++-------- .../test/scala/cats/tests/SyntaxSuite.scala | 17 ++++++++++++++ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/core/src/main/scala/cats/syntax/parallel.scala b/core/src/main/scala/cats/syntax/parallel.scala index 6059f365a8..8ba0f5e00a 100644 --- a/core/src/main/scala/cats/syntax/parallel.scala +++ b/core/src/main/scala/cats/syntax/parallel.scala @@ -118,29 +118,34 @@ final class ParallelFlatSequenceOps[T[_], M[_], A](private val tmta: T[M[T[A]]]) } final class ParallelUnorderedSequenceOps[T[_], M[_], A](private val tmta: T[M[A]]) extends AnyVal { - def parUnorderedFlatSequence[F[_]: CommutativeApplicative](implicit P: Parallel[M, F], - Tutraverse: UnorderedTraverse[T]): M[T[A]] = + def parUnorderedSequence[F[_]](implicit P: Parallel[M, F], + F: CommutativeApplicative[F], + Tutraverse: UnorderedTraverse[T]): M[T[A]] = Parallel.parUnorderedSequence(tmta) } final class ParallelUnorderedTraverseOps[T[_], A](private val ta: T[A]) extends AnyVal { - def parUnorderedFlatTraverse[M[_], F[_]: CommutativeApplicative, B]( + def parUnorderedTraverse[M[_], F[_], B]( f: A => M[B] - )(implicit P: Parallel[M, F], Tutraverse: UnorderedTraverse[T]): M[T[B]] = + )(implicit P: Parallel[M, F], F: CommutativeApplicative[F], Tutraverse: UnorderedTraverse[T]): M[T[B]] = Parallel.parUnorderedTraverse(ta)(f) } final class ParallelUnorderedFlatSequenceOps[T[_], M[_], A](private val tmta: T[M[T[A]]]) extends AnyVal { - def parUnorderedFlatSequence[F[_]: CommutativeApplicative](implicit P: Parallel[M, F], - Tflatmap: FlatMap[T], - Tutraverse: UnorderedTraverse[T]): M[T[A]] = + def parUnorderedFlatSequence[F[_]](implicit P: Parallel[M, F], + Tflatmap: FlatMap[T], + F: CommutativeApplicative[F], + Tutraverse: UnorderedTraverse[T]): M[T[A]] = Parallel.parUnorderedFlatSequence(tmta) } final class ParallelUnorderedFlatTraverseOps[T[_], A](private val ta: T[A]) extends AnyVal { - def parUnorderedFlatTraverse[M[_], F[_]: CommutativeApplicative, B]( + def parUnorderedFlatTraverse[M[_], F[_], B]( f: A => M[T[B]] - )(implicit P: Parallel[M, F], Tflatmap: FlatMap[T], Tutraverse: UnorderedTraverse[T]): M[T[B]] = + )(implicit P: Parallel[M, F], + F: CommutativeApplicative[F], + Tflatmap: FlatMap[T], + Tutraverse: UnorderedTraverse[T]): M[T[B]] = Parallel.parUnorderedFlatTraverse(ta)(f) } diff --git a/tests/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/src/test/scala/cats/tests/SyntaxSuite.scala index 83feb8290f..cba4cfc17a 100644 --- a/tests/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/src/test/scala/cats/tests/SyntaxSuite.scala @@ -188,6 +188,23 @@ object SyntaxSuite val mb3: M[B] = mab <&> ma } + def testParallelUnorderedTraverse[M[_]: Monad, F[_]: CommutativeApplicative, T[_]: UnorderedTraverse: FlatMap, A, B]( + implicit P: Parallel[M, F] + ): Unit = { + val ta = mock[T[A]] + val f = mock[A => M[B]] + val mtb = ta.parUnorderedTraverse(f) + + val tma = mock[T[M[A]]] + val mta = tma.parUnorderedSequence + + val tmta = mock[T[M[T[A]]]] + val mta2 = tmta.parUnorderedFlatSequence + + val g = mock[A => M[T[B]]] + val mtb2 = ta.parUnorderedFlatTraverse(g) + } + 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]]] From 6f4d1d6ca7d4b77366ac3a6d98ef484ebf1225a5 Mon Sep 17 00:00:00 2001 From: Matthias Berndt Date: Sat, 3 Aug 2019 01:17:32 +0200 Subject: [PATCH 3/3] coalesce ParallelUnorderedFlatTraverseOps and ParallelUnorderedTraverseOps into one --- .../src/main/scala/cats/syntax/parallel.scala | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/core/src/main/scala/cats/syntax/parallel.scala b/core/src/main/scala/cats/syntax/parallel.scala index 8ba0f5e00a..b56f5844d3 100644 --- a/core/src/main/scala/cats/syntax/parallel.scala +++ b/core/src/main/scala/cats/syntax/parallel.scala @@ -72,11 +72,6 @@ trait ParallelUnorderedTraverseSyntax { ): ParallelUnorderedSequenceOps[T, M, A] = new ParallelUnorderedSequenceOps[T, M, A](tma) - implicit final def catsSyntaxParallelUnorderedFlatTraverse[T[_], A]( - ta: T[A] - ): ParallelUnorderedFlatTraverseOps[T, A] = - new ParallelUnorderedFlatTraverseOps[T, A](ta) - implicit final def catsSyntaxParallelUnorderedFlatSequence[T[_], M[_], A]( tmta: T[M[T[A]]] ): ParallelUnorderedFlatSequenceOps[T, M, A] = @@ -129,17 +124,7 @@ final class ParallelUnorderedTraverseOps[T[_], A](private val ta: T[A]) extends f: A => M[B] )(implicit P: Parallel[M, F], F: CommutativeApplicative[F], Tutraverse: UnorderedTraverse[T]): M[T[B]] = Parallel.parUnorderedTraverse(ta)(f) -} -final class ParallelUnorderedFlatSequenceOps[T[_], M[_], A](private val tmta: T[M[T[A]]]) extends AnyVal { - def parUnorderedFlatSequence[F[_]](implicit P: Parallel[M, F], - Tflatmap: FlatMap[T], - F: CommutativeApplicative[F], - Tutraverse: UnorderedTraverse[T]): M[T[A]] = - Parallel.parUnorderedFlatSequence(tmta) -} - -final class ParallelUnorderedFlatTraverseOps[T[_], A](private val ta: T[A]) extends AnyVal { def parUnorderedFlatTraverse[M[_], F[_], B]( f: A => M[T[B]] )(implicit P: Parallel[M, F], @@ -149,6 +134,14 @@ final class ParallelUnorderedFlatTraverseOps[T[_], A](private val ta: T[A]) exte Parallel.parUnorderedFlatTraverse(ta)(f) } +final class ParallelUnorderedFlatSequenceOps[T[_], M[_], A](private val tmta: T[M[T[A]]]) extends AnyVal { + def parUnorderedFlatSequence[F[_]](implicit P: Parallel[M, F], + Tflatmap: FlatMap[T], + F: CommutativeApplicative[F], + Tutraverse: UnorderedTraverse[T]): M[T[A]] = + Parallel.parUnorderedFlatSequence(tmta) +} + final class ParallelApOps[M[_], A](private val ma: M[A]) extends AnyVal { def &>[F[_], B](mb: M[B])(implicit P: Parallel[M, F]): M[B] =