Skip to content

Commit aadce06

Browse files
authored
Merge pull request #4243 from TonioGela/main
Added `parFlatMapN`
2 parents 54bbe14 + 325b4b4 commit aadce06

File tree

3 files changed

+63
-4
lines changed

3 files changed

+63
-4
lines changed

project/Boilerplate.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,9 @@ object Boilerplate {
341341
- /** @group ParMapArity */
342342
- def parMap$arity[M[_], ${`A..N`}, Z]($fparams)(f: (${`A..N`}) => Z)(implicit p: NonEmptyParallel[M]): M[Z] =
343343
- p.flatMap.map(${nestedExpansion.products}) { case ${nestedExpansion.`(a..n)`} => f(${`a..n`}) }
344+
-
345+
- def parFlatMap$arity[M[_], ${`A..N`}, Z]($fparams)(f: (${`A..N`}) => M[Z])(implicit p: NonEmptyParallel[M]): M[Z] =
346+
- p.flatMap.flatMap(${nestedExpansion.products}) { case ${nestedExpansion.`(a..n)`} => f(${`a..n`}) }
344347
|}
345348
"""
346349
}
@@ -464,6 +467,11 @@ object Boilerplate {
464467
else
465468
s"def parMapN[Z](f: (${`A..N`}) => Z)(implicit p: NonEmptyParallel[M]): M[Z] = Parallel.parMap$arity($tupleArgs)(f)"
466469

470+
val parFlatMap =
471+
if (arity == 1)
472+
s"def parFlatMap[Z](f: (${`A..N`}) => M[Z])(implicit p: NonEmptyParallel[M]): M[Z] = p.flatMap.flatMap($tupleArgs)(f)"
473+
else
474+
s"def parFlatMapN[Z](f: (${`A..N`}) => M[Z])(implicit p: NonEmptyParallel[M]): M[Z] = Parallel.parFlatMap$arity($tupleArgs)(f)"
467475
val parTupled =
468476
if (arity == 1) ""
469477
else
@@ -482,6 +490,7 @@ object Boilerplate {
482490
-private[syntax] final class Tuple${arity}ParallelOps[M[_], ${`A..N`}](private val $tupleTpe) extends Serializable {
483491
- $parMap
484492
- $parTupled
493+
- $parFlatMap
485494
-}
486495
|
487496
"""

tests/shared/src/test/scala/cats/tests/ParallelSuite.scala

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,38 @@ class ParallelSuite
390390
}
391391
}
392392

393+
test("ParFlatMapN over List should be consistent with parMapN flatten") {
394+
forAll { (as: List[Int], bs: List[Int], cs: List[Int], mf: (Int, Int, Int) => List[Int]) =>
395+
assert((as, bs, cs).parFlatMapN(mf) == (as, bs, cs).parMapN(mf).flatten)
396+
}
397+
}
398+
399+
test("ParFlatMapN over NonEmptyList should be consistent with parMapN flatten") {
400+
forAll {
401+
(as: NonEmptyList[Int], bs: NonEmptyList[Int], cs: NonEmptyList[Int], mf: (Int, Int, Int) => NonEmptyList[Int]) =>
402+
assert((as, bs, cs).parFlatMapN(mf) == (as, bs, cs).parMapN(mf).flatten)
403+
}
404+
}
405+
406+
test("ParFlatMap over List should be consistent with flatmap") {
407+
forAll { (as: List[Int], mf: Int => List[Int]) =>
408+
assert(Tuple1(as).parFlatMap(mf) == Tuple1(as).flatMap(mf))
409+
}
410+
}
411+
412+
test("ParFlatMap over NonEmptyList should be consistent with flatmap") {
413+
forAll { (as: NonEmptyList[Int], mf: Int => NonEmptyList[Int]) =>
414+
assert(Tuple1(as).parFlatMap(mf) == Tuple1(as).flatMap(mf))
415+
}
416+
}
417+
418+
test("ParMapN over f should be consistent with parFlatMapN over f lifted in List") {
419+
forAll { (as: List[Int], bs: List[Int], f: (Int, Int) => Int) =>
420+
val mf: (Int, Int) => List[Int] = (a, b) => f(a, b).pure[List]
421+
assert((as, bs).parMapN(f) == (as, bs).parFlatMapN(mf))
422+
}
423+
}
424+
393425
test("ParTupled of NonEmptyList should be consistent with ParMap of Tuple.apply") {
394426
forAll { (fa: NonEmptyList[Int], fb: NonEmptyList[Int], fc: NonEmptyList[Int], fd: NonEmptyList[Int]) =>
395427
assert((fa, fb, fc, fd).parTupled === ((fa, fb, fc, fd).parMapN(Tuple4.apply)))

tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,14 +241,32 @@ object SyntaxSuite {
241241
}
242242

243243
def testParallelTuple[M[_]: Monad, F[_], A, B, C, Z](implicit P: NonEmptyParallel.Aux[M, F]) = {
244-
val tfabc = mock[(M[A], M[B], M[C])]
245244
val fa = mock[M[A]]
246245
val fb = mock[M[B]]
247246
val fc = mock[M[C]]
248-
val f = mock[(A, B, C) => Z]
249247

250-
tfabc.parMapN(f)
251-
(fa, fb, fc).parMapN(f)
248+
val tfabc = mock[(M[A], M[B], M[C])]
249+
val fthree = mock[(A, B, C) => Z]
250+
val mfthree = mock[(A, B, C) => M[Z]]
251+
252+
tfabc.parMapN(fthree)
253+
(fa, fb, fc).parMapN(fthree)
254+
tfabc.parFlatMapN(mfthree)
255+
(fa, fb, fc).parFlatMapN(mfthree)
256+
257+
val tfab = mock[(M[A], M[B])]
258+
val ftwo = mock[(A, B) => Z]
259+
val mftwo = mock[(A, B) => M[Z]]
260+
261+
tfab.parMapN(ftwo)
262+
(fa, fb).parMapN(ftwo)
263+
tfab.parFlatMapN(mftwo)
264+
(fa, fb).parFlatMapN(mftwo)
265+
266+
val tfa = mock[Tuple1[M[A]]]
267+
val mfone = mock[A => M[Z]]
268+
269+
tfa.parFlatMap(mfone)
252270
}
253271

254272
def testParallelBi[M[_], F[_], T[_, _]: Bitraverse, A, B, C, D](implicit P: Parallel.Aux[M, F]): Unit = {

0 commit comments

Comments
 (0)