Skip to content

Commit

Permalink
add unordered parallel variants of (flat)traverse and (flat)sequence (#…
Browse files Browse the repository at this point in the history
…2946)

* add unordered parallel variants of (flat)traverse and (flat)sequence

* add some tests and fix some bugs

* coalesce ParallelUnorderedFlatTraverseOps and ParallelUnorderedTraverseOps into one
  • Loading branch information
mberndt123 authored and kailuowang committed Aug 5, 2019
1 parent a786f15 commit 28ecdcb
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 1 deletion.
20 changes: 20 additions & 0 deletions core/src/main/scala/cats/Parallel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/scala/cats/syntax/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ abstract class AllSyntaxBinCompat
with AllSyntaxBinCompat3
with AllSyntaxBinCompat4
with AllSyntaxBinCompat5
with AllSyntaxBinCompat6

trait AllSyntax
extends AlternativeSyntax
Expand Down Expand Up @@ -90,3 +91,5 @@ trait AllSyntaxBinCompat4
with BitraverseSyntaxBinCompat0

trait AllSyntaxBinCompat5 extends ParallelBitraverseSyntax

trait AllSyntaxBinCompat6 extends ParallelUnorderedTraverseSyntax
1 change: 1 addition & 0 deletions core/src/main/scala/cats/syntax/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
50 changes: 49 additions & 1 deletion core/src/main/scala/cats/syntax/parallel.scala
Original file line number Diff line number Diff line change
@@ -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 {

Expand Down Expand Up @@ -61,6 +61,24 @@ 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 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)
Expand Down Expand Up @@ -94,6 +112,36 @@ 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 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 parUnorderedTraverse[M[_], F[_], B](
f: A => M[B]
)(implicit P: Parallel[M, F], F: CommutativeApplicative[F], Tutraverse: UnorderedTraverse[T]): M[T[B]] =
Parallel.parUnorderedTraverse(ta)(f)

def parUnorderedFlatTraverse[M[_], F[_], B](
f: A => M[T[B]]
)(implicit P: Parallel[M, F],
F: CommutativeApplicative[F],
Tflatmap: FlatMap[T],
Tutraverse: UnorderedTraverse[T]): M[T[B]] =
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] =
Expand Down
17 changes: 17 additions & 0 deletions tests/src/test/scala/cats/tests/SyntaxSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]]]
Expand Down

0 comments on commit 28ecdcb

Please sign in to comment.