From e4bea48d868f616cb42258f4c1ada7918cae4680 Mon Sep 17 00:00:00 2001 From: Georgi Krastev Date: Sat, 8 May 2021 22:11:17 +0200 Subject: [PATCH] Optimize cats-core boilerplate --- project/Boilerplate.scala | 16 ++--- project/TupleBifunctorInstancesBoiler.scala | 20 ++++--- project/TupleBitraverseInstancesBoiler.scala | 43 +++++++++----- project/TupleMonadInstancesBoiler.scala | 40 ++++++------- project/TupleShowInstancesBoiler.scala | 4 +- ...upleUnorderedFoldableInstancesBoiler.scala | 58 ++++++++++--------- 6 files changed, 95 insertions(+), 86 deletions(-) diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index 978c99ffafe..18d0f38224c 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -74,10 +74,6 @@ object Boilerplate { if (arity <= 2) "(*, *)" else `A..(N - 2)`.mkString("(", ", ", ", *, *)") val `a..(n - 1)` = (0 until (arity - 1)).map(n => s"a$n") - val `fa._1..fa._(n - 2)` = - if (arity <= 2) "" else (0 until (arity - 2)).map(n => s"fa._${n + 1}").mkString("", ", ", ", ") - val `pure(fa._1..(n - 2))` = - if (arity <= 2) "" else (0 until (arity - 2)).map(n => s"G.pure(fa._${n + 1})").mkString("", ", ", ", ") val `a0, a(n - 1)` = if (arity <= 1) "" else `a..(n - 1)`.mkString(", ") val `[A0, A(N - 1)]` = if (arity <= 1) "" else `A..(N - 1)`.mkString("[", ", ", "]") val `(A0, A(N - 1))` = @@ -87,19 +83,15 @@ object Boilerplate { val `(A..N - 1, *)` = if (arity == 1) "Tuple1" else `A..(N - 1)`.mkString("(", ", ", ", *)") - val `(fa._1..(n - 1))` = - if (arity <= 1) "Tuple1.apply" else (0 until (arity - 1)).map(n => s"fa._${n + 1}").mkString("(", ", ", ", _)") def `A0, A(N - 1)&`(a: String): String = if (arity <= 1) s"Tuple1[$a]" else `A..(N - 1)`.mkString("(", ", ", s", $a)") - - def `fa._1..(n - 1) & `(a: String): String = - if (arity <= 1) s"Tuple1($a)" else (0 until (arity - 1)).map(n => s"fa._${n + 1}").mkString("(", ", ", s", $a)") - - def `constraints A..N`(c: String): String = synTypes.map(tpe => s"$tpe: $c[$tpe]").mkString("(implicit ", ", ", ")") + def `constraints A..N`(c: String): String = + synTypes.map(tpe => s"$tpe: $c[$tpe]").mkString("(implicit ", ", ", ")") def `constraints A..(N-1)`(c: String): String = if (arity <= 1) "" else `A..(N - 1)`.map(tpe => s"$tpe: $c[$tpe]").mkString("(implicit ", ", ", ")") - def `parameters A..(N-1)`(c: String): String = `A..(N - 1)`.map(tpe => s"$tpe: $c[$tpe]").mkString(", ") + def `parameters A..(N-1)`(c: String): String = + `A..(N - 1)`.map(tpe => s"$tpe: $c[$tpe]").mkString(", ") } trait Template { diff --git a/project/TupleBifunctorInstancesBoiler.scala b/project/TupleBifunctorInstancesBoiler.scala index e88baaf60a1..b4e151ee989 100644 --- a/project/TupleBifunctorInstancesBoiler.scala +++ b/project/TupleBifunctorInstancesBoiler.scala @@ -5,7 +5,7 @@ import Boilerplate.{Template, TemplateVals} import sbt.File object GenTupleBifunctorInstances extends Template { - override def range = 1 to 11 + override def range = 2 to 11 override def filename(root: sbt.File): File = root / "cats" / "instances" / "NTupleBifunctorInstances.scala" @@ -18,15 +18,17 @@ object GenTupleBifunctorInstances extends Template { |package instances | |private[cats] trait NTupleBifunctorInstances { -${if (arity > 1) - block""" + | + | private def instance[F[_, _]](bim: (F[Any, Any], Any => Any, Any => Any) => F[Any, Any]): Bifunctor[F] = + | new Bifunctor[F] { + | def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D] = + | bim(fab.asInstanceOf[F[Any, Any]], f.asInstanceOf[Any => Any], g.asInstanceOf[Any => Any]).asInstanceOf[F[C, D]] + | } + - - implicit final def catsStdBifunctorForTuple$arity${`[A0, A(N - 2)]`}: Bifunctor[${`(A..N - 2, *, *)`}] = - - new Bifunctor[${`(A..N - 2, *, *)`}] { - - def bimap[A, B, C, D](fa: (${`A0, A(N - 2)`}A, B))(f: A => C, g: B => D): (${`A0, A(N - 2)`}C, D) = (${`fa._1..fa._(n - 2)`}f(fa._${arity - 1}), g(fa._$arity)) - - }""" - else - block""" - -"""} + - instance[${`(A..N - 2, *, *)`}] { (fab, f, g) => + - fab.copy(_${arity - 1} = f(fab._${arity - 1}), _$arity = g(fab._$arity)) + - } |}""" } } diff --git a/project/TupleBitraverseInstancesBoiler.scala b/project/TupleBitraverseInstancesBoiler.scala index 4933d44f072..5901b26cd1f 100644 --- a/project/TupleBitraverseInstancesBoiler.scala +++ b/project/TupleBitraverseInstancesBoiler.scala @@ -5,7 +5,7 @@ import Boilerplate.{Template, TemplateVals} import sbt.File object GenTupleBitraverseInstances extends Template { - override def range = 1 to 11 + override def range = 2 to 11 override def filename(root: sbt.File): File = root / "cats" / "instances" / "NTupleBitraverseInstances.scala" @@ -18,20 +18,35 @@ object GenTupleBitraverseInstances extends Template { |package instances | |private[cats] trait NTupleBitraverseInstances { -${if (arity > 1) - block""" + | protected type γ[_] + | + | private def instance[F[_, _] <: Product]( + | bitrav: (F[Any, Any], Applicative[γ], Any => γ[Any], Any => γ[Any]) => γ[F[Any, Any]] + | ): Bitraverse[F] = new Bitraverse[F] { + | def bitraverse[G[_], A, B, C, D](fab: F[A, B])(f: A => G[C], g: B => G[D])(implicit G: Applicative[G]): G[F[C, D]] = + | bitrav( + | fab.asInstanceOf[F[Any, Any]], + | G.asInstanceOf[Applicative[γ]], + | f.asInstanceOf[Any => γ[Any]], + | g.asInstanceOf[Any => γ[Any]] + | ).asInstanceOf[G[F[C, D]]] + | + | @inline private def last1[A, B](fab: F[A, B]): A = + | fab.productElement(fab.productArity - 2).asInstanceOf[A] + | @inline private def last2[A, B](fab: F[A, B]): B = + | fab.productElement(fab.productArity - 1).asInstanceOf[B] + | def bifoldLeft[A, B, C](fab: F[A, B], c: C)(f: (C, A) => C, g: (C, B) => C): C = + | g(f(c, last1(fab)), last2(fab)) + | def bifoldRight[A, B, C](fab: F[A, B], c: Eval[C])(f: (A, Eval[C]) => Eval[C], g: (B, Eval[C]) => Eval[C]): Eval[C] = + | g(last2(fab), f(last1(fab), c)) + | } + - - implicit final def catsStdBitraverseForTuple$arity${`[A0, A(N - 2)]`}: Bitraverse[${`(A..N - 2, *, *)`}] = - - new Bitraverse[${`(A..N - 2, *, *)`}] { - - def bitraverse[G[_], A, B, C, D](fa: (${`A0, A(N - 2)`}A, B))(f: A => G[C], g: B => G[D])(implicit G: Applicative[G]): G[(${`A0, A(N - 2)`}C, D)] = - - G.tuple$arity(${`pure(fa._1..(n - 2))`}f(fa._${arity - 1}), g(fa._$arity)) - - def bifoldLeft[A, B, C](fa: (${`A0, A(N - 2)`}A, B), c: C)(f: (C, A) => C, g: (C, B) => C): C = - - g(f(c, fa._${arity - 1}), fa._$arity) - - def bifoldRight[A, B, C](fa: (${`A0, A(N - 2)`}A, B), c: Eval[C])(f: (A, Eval[C]) => Eval[C], g: (B, Eval[C]) => Eval[C]): Eval[C] = - - g(fa._$arity, f(fa._${arity - 1}, c)) - - }""" - else - block""" - -"""} + - instance { (fab, G, f, g) => + - G.map2(f(fab._${arity - 1}), g(fab._$arity)) { (x, y) => + - fab.copy(_${arity - 1} = x, _$arity = y) + - } + - } |}""" } } diff --git a/project/TupleMonadInstancesBoiler.scala b/project/TupleMonadInstancesBoiler.scala index c38cb33449b..cfc277b2d35 100644 --- a/project/TupleMonadInstancesBoiler.scala +++ b/project/TupleMonadInstancesBoiler.scala @@ -56,20 +56,21 @@ object GenTupleMonadInstances extends Template { |import scala.annotation.tailrec | |private[cats] trait NTupleMonadInstances extends NTupleMonadInstances1 { + | + | private def instance[F[_] <: Product](cofMap: (F[Any], F[Any] => Any) => F[Any]): Comonad[F] = + | new Comonad[F] { + | def coflatMap[A, B](fa: F[A])(f: F[A] => B) = + | cofMap(fa.asInstanceOf[F[Any]], f.asInstanceOf[F[Any] => Any]).asInstanceOf[F[B]] + | def extract[A](fa: F[A]) = + | fa.productElement(fa.productArity - 1).asInstanceOf[A] + | def map[A, B](fa: F[A])(f: A => B) = + | coflatMap(fa)(fa => f(extract(fa))) + | } + - - implicit final def catsStdInstancesForTuple$arity${`[A0, A(N - 1)]`}: Comonad[${`(A..N - 1, *)`}] = - - new Comonad[${`(A..N - 1, *)`}] { - - def coflatMap[A, B](fa: ${`A0, A(N - 1)&`("A")})(f: (${`A0, A(N - 1)&`("A")}) => B): ${`A0, A(N - 1)&`( - "B" - )} = ${`fa._1..(n - 1) & `( - "f(fa)" - )} - - def extract[A](fa: ${`A0, A(N - 1)&`("A")}): A = fa._$arity - - override def map[A, B](fa: ${`A0, A(N - 1)&`("A")})(f: A => B): ${`A0, A(N - 1)&`("B")} = - - ${`fa._1..(n - 1) & `(s"f(fa._$arity)")} - - override def coflatten[A](fa: ${`A0, A(N - 1)&`("A")}): $coflattenReturn = ${`fa._1..(n - 1) & `("fa")} - - } + - instance((fa, f) => fa.copy(_$arity = f(fa))) |} - |private[cats] sealed trait NTupleMonadInstances1 extends NTupleMonadInstances2 { + |private[cats] sealed trait NTupleMonadInstances1 extends NTupleMonadInstances2 { this: NTupleMonadInstances => - implicit final def catsStdCommutativeMonadForTuple$arity${`[A0, A(N - 1)]`}${`constraints A..(N-1)`( "CommutativeMonoid" )}: CommutativeMonad[${`(A..N - 1, *)`}] = @@ -77,28 +78,25 @@ object GenTupleMonadInstances extends Template { - def pure[A](a: A): ${`A0, A(N - 1)&`("A")} = $monadPureMethod - } |} - |private[cats] sealed trait NTupleMonadInstances2 extends NTupleMonadInstances3 { + |private[cats] sealed trait NTupleMonadInstances2 extends NTupleMonadInstances3 { this: NTupleMonadInstances => - implicit final def catsStdCommutativeFlatMapForTuple$arity${`[A0, A(N - 1)]`}${`constraints A..(N-1)`( "CommutativeSemigroup" )}: CommutativeFlatMap[${`(A..N - 1, *)`}] = - new FlatMapTuple$arity${`[A0, A(N - 1)]`}(${`A0, A(N - 1)`}) with CommutativeFlatMap[${`(A..N - 1, *)`}] |} - |private[cats] sealed trait NTupleMonadInstances3 extends NTupleMonadInstances4 { + |private[cats] sealed trait NTupleMonadInstances3 extends NTupleMonadInstances4 { this: NTupleMonadInstances => - implicit def catsStdMonadForTuple$arity${`[A0, A(N - 1)]`}${`constraints A..(N-1)`("Monoid")}: Monad[${`(A..N - 1, *)`}] = - new FlatMapTuple$arity${`[A0, A(N - 1)]`}(${`A0, A(N - 1)`}) with Monad[${`(A..N - 1, *)`}] { - def pure[A](a: A): ${`A0, A(N - 1)&`("A")} = $monadPureMethod - } |} - |private[cats] sealed trait NTupleMonadInstances4 extends NTupleMonadInstances5 { + |private[cats] sealed trait NTupleMonadInstances4 extends NTupleMonadInstances5 { this: NTupleMonadInstances => - implicit def catsStdFlatMapForTuple$arity${`[A0, A(N - 1)]`}${`constraints A..(N-1)`("Semigroup")}: FlatMap[${`(A..N - 1, *)`}] = - new FlatMapTuple$arity${`[A0, A(N - 1)]`}(${`A0, A(N - 1)`}) |} - |private[cats] sealed trait NTupleMonadInstances5 { + |private[cats] sealed trait NTupleMonadInstances5 { this: NTupleMonadInstances => - implicit def catsStdInvariantForTuple$arity${`[A0, A(N - 1)]`}: Invariant[${`(A..N - 1, *)`}] = - - new Invariant[${`(A..N - 1, *)`}] { - - def imap[A, B](fa: ${`A0, A(N - 1)&`("A")})(f: A => B)(g: B => A): ${`A0, A(N - 1)&`("B")} = - - ${`fa._1..(n - 1) & `(s"f(fa._$arity)")} - - } + - catsStdInstancesForTuple$arity |} - -private[instances] class $flatMapTupleClass${`[A0, A(N - 1)]`}(${`parameters A..(N-1)`("Semigroup")}) extends FlatMap[${`(A..N - 1, *)`}] { @@ -107,7 +105,7 @@ object GenTupleMonadInstances extends Template { - override def product[A, B](fa: ${`A0, A(N - 1)&`("A")}, fb: ${`A0, A(N - 1)&`("B")}): ${`A0, A(N - 1)&`("(A, B)")} = - ${`combine A..(N - 1)`("fa", "fb", s"(fa._$arity, fb._$arity)")} - override def map[A, B](fa: ${`A0, A(N - 1)&`("A")})(f: A => B): ${`A0, A(N - 1)&`("B")} = - - ${`fa._1..(n - 1) & `(s"f(fa._$arity)")} + - fa.copy(_$arity = f(fa._$arity)) - def flatMap[A, B](fa: ${`A0, A(N - 1)&`("A")})(f: A => ${`A0, A(N - 1)&`("B")}): ${`A0, A(N - 1)&`("B")} = { ${if (arity > 1) block""" - val xb = f(fa._$arity) diff --git a/project/TupleShowInstancesBoiler.scala b/project/TupleShowInstancesBoiler.scala index f3273683d8a..b1e4ae2b627 100644 --- a/project/TupleShowInstancesBoiler.scala +++ b/project/TupleShowInstancesBoiler.scala @@ -26,9 +26,7 @@ object GenTupleShowInstances extends Template { | |private[cats] trait NTupleShowInstances { - implicit final def catsStdShowForTuple$arity[${`A..N`}]${`constraints A..N`("Show")}: Show[${`(A..N)`}] = - - new Show[${`(A..N)`}] { - - def show(f: ${`(A..N)`}): String = $showMethod - - } + - f => $showMethod |}""" } } diff --git a/project/TupleUnorderedFoldableInstancesBoiler.scala b/project/TupleUnorderedFoldableInstancesBoiler.scala index cf9fbfe8d46..224e277f736 100644 --- a/project/TupleUnorderedFoldableInstancesBoiler.scala +++ b/project/TupleUnorderedFoldableInstancesBoiler.scala @@ -18,33 +18,37 @@ object GenTupleUnorderedFoldableInstances extends Template { |package instances | |private[cats] trait NTupleUnorderedFoldableInstances { -- implicit final def catsUnorderedFoldableInstancesForTuple$arity${`[A0, A(N - 1)]`}: Traverse[${`(A..N - 1, *)`}] with Reducible[${`(A..N - 1, *)`}] = -- new Traverse[${`(A..N - 1, *)`}] with Reducible[${`(A..N - 1, *)`}] { -- def traverse[G[_], A, B](fa: ${`A0, A(N - 1)&`( - "A" - )})(f: A => G[B])(implicit G: Applicative[G]): G[${`A0, A(N - 1)&`( - "B" - )}] = -- G.map(f(fa._$arity))(${`(fa._1..(n - 1))`}) -- def foldLeft[A, B](fa: ${`A0, A(N - 1)&`("A")}, b: B)(f: (B, A) => B): B = f(b, fa._$arity) -- def foldRight[A, B](fa: ${`A0, A(N - 1)&`("A")}, lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = f(fa._$arity, lb) -- override def map[A, B](fa: ${`A0, A(N - 1)&`("A")})(f: A => B): ${`A0, A(N - 1)&`("B")} = -- ${`fa._1..(n - 1) & `(s"f(fa._$arity)")} -- override def foldMap[A, B](fa: ${`A0, A(N - 1)&`("A")})(f: A => B)(implicit B: Monoid[B]): B = f(fa._$arity) -- override def reduce[A](fa: ${`A0, A(N - 1)&`("A")})(implicit A: Semigroup[A]): A = fa._$arity -- def reduceLeftTo[A, B](fa: ${`A0, A(N - 1)&`("A")})(f: A => B)(g: (B, A) => B): B = f(fa._$arity) -- override def reduceLeft[A](fa: ${`A0, A(N - 1)&`("A")})(f: (A, A) => A): A = fa._$arity -- override def reduceLeftToOption[A, B](fa: ${`A0, A(N - 1)&`("A")})(f: A => B)(g: (B, A) => B): Option[B] = Some(f(fa._$arity)) -- override def reduceRight[A](fa: ${`A0, A(N - 1)&`("A")})(f: (A, Eval[A]) => Eval[A]): Eval[A] = Now(fa._$arity) -- def reduceRightTo[A, B](fa: ${`A0, A(N - 1)&`("A")})(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = Now(f(fa._$arity)) -- override def reduceRightToOption[A, B](fa: ${`A0, A(N - 1)&`("A")})(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[Option[B]] = Now(Some(f(fa._$arity))) -- override def reduceMap[A, B](fa: ${`A0, A(N - 1)&`("A")})(f: A => B)(implicit B: Semigroup[B]): B = f(fa._$arity) -- override def size[A](fa: ${`A0, A(N - 1)&`("A")}): Long = 1L -- override def get[A](fa: ${`A0, A(N - 1)&`("A")})(idx: Long): Option[A] = if (idx == 0L) Some(fa._$arity) else None -- override def exists[A](fa: ${`A0, A(N - 1)&`("A")})(p: A => Boolean): Boolean = p(fa._$arity) -- override def forall[A](fa: ${`A0, A(N - 1)&`("A")})(p: A => Boolean): Boolean = p(fa._$arity) -- override def isEmpty[A](fa: ${`A0, A(N - 1)&`("A")}): Boolean = false -- } + | protected type γ[_] + | + | private def instance[F[_] <: Product]( + | trav: (F[Any], Applicative[γ], Any => γ[Any]) => γ[F[Any]] + | ): Traverse[F] with Reducible[F] = + | new Traverse[F] with Reducible[F] { + | def traverse[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Applicative[G]) = + | trav(fa.asInstanceOf[F[Any]], G.asInstanceOf[Applicative[γ]], f.asInstanceOf[Any => γ[Any]]).asInstanceOf[G[F[B]]] + | @inline private def last[A](fa: F[A]): A = + | fa.productElement(fa.productArity - 1).asInstanceOf[A] + | def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B = f(b, last(fa)) + | def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = f(last(fa), lb) + | override def foldMap[A, B](fa: F[A])(f: A => B)(implicit B: Monoid[B]): B = f(last(fa)) + | override def reduce[A](fa: F[A])(implicit A: Semigroup[A]): A = last(fa) + | def reduceLeftTo[A, B](fa: F[A])(f: A => B)(g: (B, A) => B): B = f(last(fa)) + | override def reduceLeft[A](fa: F[A])(f: (A, A) => A): A = last(fa) + | override def reduceLeftToOption[A, B](fa: F[A])(f: A => B)(g: (B, A) => B): Option[B] = Some(f(last(fa))) + | override def reduceRight[A](fa: F[A])(f: (A, Eval[A]) => Eval[A]): Eval[A] = Now(last(fa)) + | def reduceRightTo[A, B](fa: F[A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = Now(f(last(fa))) + | override def reduceRightToOption[A, B](fa: F[A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[Option[B]] = Now(Some(f(last(fa)))) + | override def reduceMap[A, B](fa: F[A])(f: A => B)(implicit B: Semigroup[B]): B = f(last(fa)) + | override def size[A](fa: F[A]): Long = 1L + | override def get[A](fa: F[A])(idx: Long): Option[A] = if (idx == 0L) Some(last(fa)) else None + | override def exists[A](fa: F[A])(p: A => Boolean): Boolean = p(last(fa)) + | override def forall[A](fa: F[A])(p: A => Boolean): Boolean = p(last(fa)) + | override def isEmpty[A](fa: F[A]): Boolean = false + | } + - + - implicit final def catsUnorderedFoldableInstancesForTuple$arity${`[A0, A(N - 1)]`} + - : Traverse[${`(A..N - 1, *)`}] with Reducible[${`(A..N - 1, *)`}] + - = instance((fa, G, f) => G.map(f(fa._$arity))(x => fa.copy(_$arity = x))) |}""" } }