From af65abb8e817d2291334d36996149e31f393e717 Mon Sep 17 00:00:00 2001 From: Domas Poliakas Date: Wed, 6 Oct 2021 14:10:50 +0200 Subject: [PATCH 1/4] Added flatMapN --- project/Boilerplate.scala | 7 +++++++ tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index 9929241083..04e3b539db 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -516,6 +516,12 @@ object Boilerplate { else s"def traverseN[G[_]: Applicative, Z](f: (${`A..N`}) => G[Z])(implicit traverse: Traverse[F], semigroupal: Semigroupal[F]): G[F[Z]] = Semigroupal.traverse$arity($tupleArgs)(f)" + val flatMap = + if (arity == 1) + s"def flatMap[Z](f: (${`A..N`}) => F[Z])(implicit flatMap: FlatMap[F]): F[Z] = flatMap.flatMap($tupleArgs)(f)" + else + s"def flatMapN[Z](f: (${`A..N`}) => F[Z])(implicit flatMap: FlatMap[F], semigroupal: Semigroupal[F]): F[Z] = flatMap.flatten(Semigroupal.map$arity($tupleArgs)(f))" + block""" |package cats |package syntax @@ -528,6 +534,7 @@ object Boilerplate { - $map - $contramap - $imap + - $flatMap - $tupled - $traverse - def apWith[Z](f: F[(${`A..N`}) => Z])(implicit apply: Apply[F]): F[Z] = apply.ap$n(f)($tupleArgs) diff --git a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala index 66c2fb9738..375602a40e 100644 --- a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala @@ -412,10 +412,14 @@ object SyntaxSuite { val fa = a.pure[F] } - def testFlatMap[F[_]: FlatMap, A, B, C, D]: Unit = { + def testFlatMap[F[_]: FlatMap, A, B, C, D, Z]: Unit = { val a = mock[A] val returnValue = mock[F[Either[A, B]]] val done = a.tailRecM[F, B](a => returnValue) + val tfabc = mock[(F[A], F[B], F[C])] + val ff = mock[(A, B, C) => F[Z]] + + tfabc.flatMapN(ff) val x = mock[Function[A, F[B]]] val y = mock[Function[B, F[C]]] From 980c53ed1c9f126f3c92f7b18880597957c1ad79 Mon Sep 17 00:00:00 2001 From: Domas Poliakas Date: Wed, 18 May 2022 13:52:42 +0200 Subject: [PATCH 2/4] Added FlatMapArityFunctions, delegated flatMapN to those --- core/src/main/scala/cats/FlatMap.scala | 3 ++- project/Boilerplate.scala | 33 +++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/FlatMap.scala b/core/src/main/scala/cats/FlatMap.scala index fd24549e05..097c16366c 100644 --- a/core/src/main/scala/cats/FlatMap.scala +++ b/core/src/main/scala/cats/FlatMap.scala @@ -39,7 +39,8 @@ import simulacrum.noop * * Must obey the laws defined in cats.laws.FlatMapLaws. */ -@typeclass trait FlatMap[F[_]] extends Apply[F] { +@typeclass(excludeParents = List("FlatMapArityFunctions")) +trait FlatMap[F[_]] extends Apply[F] with FlatMapArityFunctions[F] { def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] /** diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index 04e3b539db..adcabc502a 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -27,6 +27,7 @@ object Boilerplate { GenSemigroupalBuilders, GenSemigroupalArityFunctions, GenApplyArityFunctions, + GenFlatMapArityFunctions, GenTupleSemigroupalSyntax, GenParallelArityFunctions, GenParallelArityFunctions2, @@ -285,6 +286,36 @@ object Boilerplate { } } + object GenFlatMapArityFunctions extends Template { + def filename(root: File) = root / "cats" / "FlatMapArityFunctions.scala" + override def range = 2 to maxArity + def content(tv: TemplateVals) = { + import tv._ + + val tpes = synTypes.map { tpe => + s"F[$tpe]" + } + val fargs = (0 until arity).map("f" + _) + val fparams = fargs.zip(tpes).map { case (v, t) => s"$v:$t" }.mkString(", ") + + block""" + |package cats + | + |/** + | * @groupprio Ungrouped 0 + | * + | * @groupname FlatMapArity flatMap arity + | * @groupdesc FlatMapArity Higher-arity flatMap methods + | * @groupprio FlatMapArity 999 + | */ + |trait FlatMapArityFunctions[F[_]] { self: FlatMap[F] => + - /** @group MapArity */ + - def flatMap$arity[${`A..N`}, Z]($fparams)(f: (${`A..N`}) => F[Z]): F[Z] = self.flatten(self.map$arity($fparams)(f)) + |} + """ + } + } + final case class ParallelNestedExpansions(arity: Int) { val products = (0 until (arity - 2)) .foldRight(s"Parallel.parProduct(m${arity - 2}, m${arity - 1})")((i, acc) => s"Parallel.parProduct(m$i, $acc)") @@ -520,7 +551,7 @@ object Boilerplate { if (arity == 1) s"def flatMap[Z](f: (${`A..N`}) => F[Z])(implicit flatMap: FlatMap[F]): F[Z] = flatMap.flatMap($tupleArgs)(f)" else - s"def flatMapN[Z](f: (${`A..N`}) => F[Z])(implicit flatMap: FlatMap[F], semigroupal: Semigroupal[F]): F[Z] = flatMap.flatten(Semigroupal.map$arity($tupleArgs)(f))" + s"def flatMapN[Z](f: (${`A..N`}) => F[Z])(implicit flatMap: FlatMap[F]): F[Z] = flatMap.flatMap$arity($tupleArgs)(f)" block""" |package cats From 6a7ddc009b277de8f1d5ad3f77812a0c16659284 Mon Sep 17 00:00:00 2001 From: Domas Poliakas Date: Wed, 18 May 2022 17:28:43 +0200 Subject: [PATCH 3/4] Fixed typo in FlatMapArityFunctions --- project/Boilerplate.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index adcabc502a..06348ce071 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -309,7 +309,7 @@ object Boilerplate { | * @groupprio FlatMapArity 999 | */ |trait FlatMapArityFunctions[F[_]] { self: FlatMap[F] => - - /** @group MapArity */ + - /** @group FlatMapArity */ - def flatMap$arity[${`A..N`}, Z]($fparams)(f: (${`A..N`}) => F[Z]): F[Z] = self.flatten(self.map$arity($fparams)(f)) |} """ From f57146a5f3e591d2105a14d8dbf63ed4b43f74c5 Mon Sep 17 00:00:00 2001 From: Domas Poliakas Date: Thu, 26 May 2022 10:48:17 +0200 Subject: [PATCH 4/4] Added tuple1 flatMap syntax test --- tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala index 375602a40e..1700a201fa 100644 --- a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala @@ -421,6 +421,11 @@ object SyntaxSuite { tfabc.flatMapN(ff) + val tfa = mock[Tuple1[F[A]]] + val ffone = mock[A => F[Z]] + + tfa.flatMap(ffone) + val x = mock[Function[A, F[B]]] val y = mock[Function[B, F[C]]] val z = mock[Function[C, F[D]]]