From 615e0dcc65435196fe973a0b368bb4c5c532905d Mon Sep 17 00:00:00 2001 From: Georgi Krastev Date: Tue, 12 Oct 2021 19:12:15 +0200 Subject: [PATCH] Make derived methods final override --- .../main/scala-3/cats/derived/DerivedEq.scala | 4 +- .../cats/derived/DerivedFoldable.scala | 54 ++++++++--------- .../scala-3/cats/derived/DerivedFunctor.scala | 6 +- .../scala-3/cats/derived/DerivedHash.scala | 4 +- .../scala-3/cats/derived/DerivedMonoid.scala | 2 +- .../derived/DerivedNonEmptyTraverse.scala | 22 ++++--- .../cats/derived/DerivedReducible.scala | 58 ++++++++++--------- .../cats/derived/DerivedSemigroup.scala | 3 +- .../cats/derived/DerivedTraverse.scala | 16 ++--- 9 files changed, 82 insertions(+), 87 deletions(-) diff --git a/core/src/main/scala-3/cats/derived/DerivedEq.scala b/core/src/main/scala-3/cats/derived/DerivedEq.scala index 0a0cee06..05d23bdd 100644 --- a/core/src/main/scala-3/cats/derived/DerivedEq.scala +++ b/core/src/main/scala-3/cats/derived/DerivedEq.scala @@ -21,11 +21,11 @@ object DerivedEq: new Coproduct[Eq, A] {} trait Product[F[x] <: Eq[x], A](using inst: K0.ProductInstances[F, A]) extends Eq[A]: - def eqv(x: A, y: A): Boolean = inst.foldLeft2(x, y)(true: Boolean)( + final override def eqv(x: A, y: A): Boolean = inst.foldLeft2(x, y)(true: Boolean)( [t] => (acc: Boolean, eqt: F[t], x: t, y: t) => Complete(!eqt.eqv(x, y))(false)(true) ) trait Coproduct[F[x] <: Eq[x], A](using inst: K0.CoproductInstances[F, A]) extends Eq[A]: - def eqv(x: A, y: A): Boolean = inst.fold2(x, y)(false)( + final override def eqv(x: A, y: A): Boolean = inst.fold2(x, y)(false)( [t] => (eqt: F[t], x: t, y: t) => eqt.eqv(x, y) ) diff --git a/core/src/main/scala-3/cats/derived/DerivedFoldable.scala b/core/src/main/scala-3/cats/derived/DerivedFoldable.scala index 6fa3ecc8..9f3bd19e 100644 --- a/core/src/main/scala-3/cats/derived/DerivedFoldable.scala +++ b/core/src/main/scala-3/cats/derived/DerivedFoldable.scala @@ -16,36 +16,28 @@ object DerivedFoldable: def foldRight[A, B](fa: T, lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = lb given [F[_], G[_]](using F: Or[F], G: Or[G]): DerivedFoldable[[x] =>> F[G[x]]] = - F.unify `compose` G.unify + F.unify.compose(G.unify) given [F[_]](using inst: K1.ProductInstances[Or, F]): DerivedFoldable[F] = - new Product(using inst.unify) {} - - given [F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedFoldable[F] = - new Coproduct(using inst.unify) {} - - trait Product[T[x[_]] <: Foldable[x], F[_]](using inst: K1.ProductInstances[T, F]) - extends Foldable[F]: - - def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B = - inst.foldLeft[A, B](fa)(b) { [f[_]] => (acc: B, tf: T[f], fa: f[A]) => - Continue(tf.foldLeft(fa, acc)(f)) - } - - def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = - inst.foldRight[A, Eval[B]](fa)(lb) { [f[_]] => (tf: T[f], fa: f[A], acc: Eval[B]) => - Continue(Eval.defer(tf.foldRight(fa, acc)(f))) - } - - trait Coproduct[T[x[_]] <: Foldable[x], F[_]](using inst: K1.CoproductInstances[T, F]) - extends Foldable[F]: - - def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B = - inst.fold[A, B](fa) { [f[_]] => (tf: T[f], fa: f[A]) => - tf.foldLeft(fa, b)(f) - } - - def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = - inst.fold[A, Eval[B]](fa) { [f[_]] => (tf: T[f], fa: f[A]) => - Eval.defer(tf.foldRight(fa, lb)(f)) - } + given K1.ProductInstances[Foldable, F] = inst.unify + new Product[Foldable, F] {} + + given [F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedFoldable[F] = + given K1.CoproductInstances[Foldable, F] = inst.unify + new Coproduct[Foldable, F] {} + + trait Product[T[x[_]] <: Foldable[x], F[_]](using inst: K1.ProductInstances[T, F]) extends Foldable[F]: + final override def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B = + inst.foldLeft[A, B](fa)(b)([f[_]] => (acc: B, tf: T[f], fa: f[A]) => Continue(tf.foldLeft(fa, acc)(f))) + + final override def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + inst.foldRight[A, Eval[B]](fa)(lb)( + [f[_]] => (tf: T[f], fa: f[A], acc: Eval[B]) => Continue(Eval.defer(tf.foldRight(fa, acc)(f))) + ) + + trait Coproduct[T[x[_]] <: Foldable[x], F[_]](using inst: K1.CoproductInstances[T, F]) extends Foldable[F]: + final override def foldLeft[A, B](fa: F[A], b: B)(f: (B, A) => B): B = + inst.fold[A, B](fa)([f[_]] => (tf: T[f], fa: f[A]) => tf.foldLeft(fa, b)(f)) + + final override def foldRight[A, B](fa: F[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = + inst.fold[A, Eval[B]](fa)([f[_]] => (tf: T[f], fa: f[A]) => Eval.defer(tf.foldRight(fa, lb)(f))) diff --git a/core/src/main/scala-3/cats/derived/DerivedFunctor.scala b/core/src/main/scala-3/cats/derived/DerivedFunctor.scala index 91ddfbd1..4430e55e 100644 --- a/core/src/main/scala-3/cats/derived/DerivedFunctor.scala +++ b/core/src/main/scala-3/cats/derived/DerivedFunctor.scala @@ -23,8 +23,8 @@ object DerivedFunctor: given [F[_]](using inst: => K1.Instances[Or, F]): DerivedFunctor[F] = given K1.Instances[Functor, F] = inst.unify - new GenericFunctor[Functor, F] {} + new Generic[Functor, F] {} - trait GenericFunctor[T[x[_]] <: Functor[x], F[_]](using inst: K1.Instances[T, F]) extends Functor[F]: - override def map[A, B](fa: F[A])(f: A => B): F[B] = + trait Generic[T[x[_]] <: Functor[x], F[_]](using inst: K1.Instances[T, F]) extends Functor[F]: + final override def map[A, B](fa: F[A])(f: A => B): F[B] = inst.map(fa: F[A])([f[_]] => (tf: T[f], fa: f[A]) => tf.map(fa)(f)) diff --git a/core/src/main/scala-3/cats/derived/DerivedHash.scala b/core/src/main/scala-3/cats/derived/DerivedHash.scala index 6fe2a028..3637a352 100644 --- a/core/src/main/scala-3/cats/derived/DerivedHash.scala +++ b/core/src/main/scala-3/cats/derived/DerivedHash.scala @@ -25,7 +25,7 @@ object DerivedHash: extends DerivedEq.Product[F, A], Hash[A]: - def hash(x: A): Int = + final override def hash(x: A): Int = val arity = x.productArity val prefix = x.productPrefix.hashCode if arity <= 0 then prefix @@ -41,5 +41,5 @@ object DerivedHash: extends DerivedEq.Coproduct[F, A], Hash[A]: - def hash(x: A): Int = + final override def hash(x: A): Int = inst.fold[Int](x)([t] => (h: F[t], x: t) => h.hash(x)) diff --git a/core/src/main/scala-3/cats/derived/DerivedMonoid.scala b/core/src/main/scala-3/cats/derived/DerivedMonoid.scala index 04d29d90..92934da2 100644 --- a/core/src/main/scala-3/cats/derived/DerivedMonoid.scala +++ b/core/src/main/scala-3/cats/derived/DerivedMonoid.scala @@ -19,4 +19,4 @@ object DerivedMonoid: trait Product[F[x] <: Monoid[x], A](using inst: K0.ProductInstances[F, A]) extends DerivedSemigroup.Product[F, A], Monoid[A]: - val empty: A = inst.construct([A] => (F: F[A]) => F.empty) + final override val empty: A = inst.construct([A] => (F: F[A]) => F.empty) diff --git a/core/src/main/scala-3/cats/derived/DerivedNonEmptyTraverse.scala b/core/src/main/scala-3/cats/derived/DerivedNonEmptyTraverse.scala index 37981264..dc354900 100644 --- a/core/src/main/scala-3/cats/derived/DerivedNonEmptyTraverse.scala +++ b/core/src/main/scala-3/cats/derived/DerivedNonEmptyTraverse.scala @@ -20,37 +20,35 @@ object DerivedNonEmptyTraverse: inst: K1.ProductInstances[DerivedTraverse.Or, F] ): DerivedNonEmptyTraverse[F] = given K1.ProductInstances[Traverse, F] = inst.unify - new ProductNonEmptyTraverse[Traverse, F](ev) with DerivedReducible.Product[Traverse, F](ev) {} + new Product[Traverse, F](ev) + with DerivedReducible.Product[Traverse, F](ev) + with DerivedTraverse.Product[Traverse, F] {} inline given [F[_]](using gen: K1.ProductGeneric[F]): DerivedNonEmptyTraverse[F] = product(K1.summonFirst[Or, gen.MirroredElemTypes, Const[Any]].unify) given [F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedNonEmptyTraverse[F] = given K1.CoproductInstances[NonEmptyTraverse, F] = inst.unify - new CoproductNonEmptyTraverse[NonEmptyTraverse, F] {} + new Coproduct[NonEmptyTraverse, F] {} - trait ProductNonEmptyTraverse[T[x[_]] <: Traverse[x], F[_]](ev: NonEmptyTraverse[?])(using + trait Product[T[x[_]] <: Traverse[x], F[_]](ev: NonEmptyTraverse[?])(using inst: K1.ProductInstances[T, F] ) extends NonEmptyTraverse[F], DerivedReducible.Product[T, F], - DerivedTraverse.ProductTraverse[T, F]: + DerivedTraverse.Product[T, F]: - // FIXME: Why is this override necessary? - override def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B]] = - super[ProductTraverse].traverse(fa)(f) - - override def nonEmptyTraverse[G[_]: Apply, A, B](fa: F[A])(f: A => G[B]): G[F[B]] = + final override def nonEmptyTraverse[G[_]: Apply, A, B](fa: F[A])(f: A => G[B]): G[F[B]] = traverse[Alt[G], A, B](fa)(f.andThen(Left.apply)) match case Left(value) => value case Right(_) => ??? - trait CoproductNonEmptyTraverse[T[x[_]] <: NonEmptyTraverse[x], F[_]](using + trait Coproduct[T[x[_]] <: NonEmptyTraverse[x], F[_]](using inst: K1.CoproductInstances[T, F] ) extends NonEmptyTraverse[F], DerivedReducible.Coproduct[T, F], - DerivedTraverse.CoproductTraverse[T, F]: + DerivedTraverse.Coproduct[T, F]: - override def nonEmptyTraverse[G[_]: Apply, A, B](fa: F[A])(f: A => G[B]): G[F[B]] = + final override def nonEmptyTraverse[G[_]: Apply, A, B](fa: F[A])(f: A => G[B]): G[F[B]] = inst.fold(fa)([f[_]] => (tf: T[f], fa: f[A]) => tf.nonEmptyTraverse(fa)(f).asInstanceOf[G[F[B]]]) private type Alt[F[_]] = [A] =>> Either[F[A], A] diff --git a/core/src/main/scala-3/cats/derived/DerivedReducible.scala b/core/src/main/scala-3/cats/derived/DerivedReducible.scala index f61ec4e8..b0ebc4a9 100644 --- a/core/src/main/scala-3/cats/derived/DerivedReducible.scala +++ b/core/src/main/scala-3/cats/derived/DerivedReducible.scala @@ -13,7 +13,7 @@ object DerivedReducible: summonInline[DerivedReducible[F]].instance given [F[_], G[_]](using F: Or[F], G: Or[G]): DerivedReducible[[x] =>> F[G[x]]] = - F.unify `compose` G.unify + F.unify.compose(G.unify) def product[F[_]](ev: Reducible[?])(using inst: K1.ProductInstances[DerivedFoldable.Or, F]): DerivedReducible[F] = given K1.ProductInstances[Foldable, F] = inst.unify @@ -27,36 +27,40 @@ object DerivedReducible: new Coproduct[Reducible, F] {} trait Product[T[x[_]] <: Foldable[x], F[_]](ev: Reducible[?])(using inst: K1.ProductInstances[T, F]) - extends DerivedFoldable.Product[T, F], Reducible[F]: + extends DerivedFoldable.Product[T, F], + Reducible[F]: private val evalNone = Eval.now(None) - def reduceLeftTo[A, B](fa: F[A])(f: A => B)(g: (B, A) => B): B = - inst.foldLeft[A, Option[B]](fa)(None)( - [f[_]] => (acc: Option[B], tf: T[f], fa: f[A]) => - acc match - case Some(b) => Continue(Some(tf.foldLeft(fa, b)(g))) - case None => Continue(tf.reduceLeftToOption(fa)(f)(g)) - ).get - - def reduceRightTo[A, B](fa: F[A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = - inst.foldRight[A, Eval[Option[B]]](fa)(evalNone)( - [f[_]] => (tf: T[f], fa: f[A], acc: Eval[Option[B]]) => - Continue(acc.flatMap { - case Some(b) => tf.foldRight(fa, Eval.now(b))(g).map(Some.apply) - case None => tf.reduceRightToOption(fa)(f)(g) - }) - ).map(_.get) + final override def reduceLeftTo[A, B](fa: F[A])(f: A => B)(g: (B, A) => B): B = + inst + .foldLeft[A, Option[B]](fa)(None)( + [f[_]] => + (acc: Option[B], tf: T[f], fa: f[A]) => + acc match + case Some(b) => Continue(Some(tf.foldLeft(fa, b)(g))) + case None => Continue(tf.reduceLeftToOption(fa)(f)(g)) + ) + .get + + final override def reduceRightTo[A, B](fa: F[A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = + inst + .foldRight[A, Eval[Option[B]]](fa)(evalNone)( + [f[_]] => + (tf: T[f], fa: f[A], acc: Eval[Option[B]]) => + Continue(acc.flatMap { + case Some(b) => tf.foldRight(fa, Eval.now(b))(g).map(Some.apply) + case None => tf.reduceRightToOption(fa)(f)(g) + }) + ) + .map(_.get) trait Coproduct[T[x[_]] <: Reducible[x], F[_]](using inst: K1.CoproductInstances[T, F]) - extends DerivedFoldable.Coproduct[T, F], Reducible[F]: + extends DerivedFoldable.Coproduct[T, F], + Reducible[F]: - def reduceLeftTo[A, B](fa: F[A])(f: A => B)(g: (B, A) => B): B = - inst.fold[A, B](fa) { [f[_]] => (tf: T[f], fa: f[A]) => - tf.reduceLeftTo(fa)(f)(g) - } + final override def reduceLeftTo[A, B](fa: F[A])(f: A => B)(g: (B, A) => B): B = + inst.fold[A, B](fa)([f[_]] => (tf: T[f], fa: f[A]) => tf.reduceLeftTo(fa)(f)(g)) - def reduceRightTo[A, B](fa: F[A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = - inst.fold[A, Eval[B]](fa) { [f[_]] => (tf: T[f], fa: f[A]) => - Eval.defer(tf.reduceRightTo(fa)(f)(g)) - } + final override def reduceRightTo[A, B](fa: F[A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = + inst.fold[A, Eval[B]](fa)([f[_]] => (tf: T[f], fa: f[A]) => Eval.defer(tf.reduceRightTo(fa)(f)(g))) diff --git a/core/src/main/scala-3/cats/derived/DerivedSemigroup.scala b/core/src/main/scala-3/cats/derived/DerivedSemigroup.scala index 8f0f8b29..742588e6 100644 --- a/core/src/main/scala-3/cats/derived/DerivedSemigroup.scala +++ b/core/src/main/scala-3/cats/derived/DerivedSemigroup.scala @@ -17,4 +17,5 @@ object DerivedSemigroup: new Product[Semigroup, A] {} trait Product[F[x] <: Semigroup[x], A](using inst: K0.ProductInstances[F, A]) extends Semigroup[A]: - def combine(x: A, y: A): A = inst.map2(x, y)([A] => (F: F[A], x: A, y: A) => F.combine(x, y)) + final override def combine(x: A, y: A): A = + inst.map2(x, y)([A] => (F: F[A], x: A, y: A) => F.combine(x, y)) diff --git a/core/src/main/scala-3/cats/derived/DerivedTraverse.scala b/core/src/main/scala-3/cats/derived/DerivedTraverse.scala index c52f8409..6d095311 100644 --- a/core/src/main/scala-3/cats/derived/DerivedTraverse.scala +++ b/core/src/main/scala-3/cats/derived/DerivedTraverse.scala @@ -23,27 +23,27 @@ object DerivedTraverse: given [F[_]](using inst: K1.ProductInstances[Or, F]): DerivedTraverse[F] = given K1.ProductInstances[Traverse, F] = inst.unify - new ProductTraverse[Traverse, F] {} + new Product[Traverse, F] {} given [F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedTraverse[F] = given K1.CoproductInstances[Traverse, F] = inst.unify - new CoproductTraverse[Traverse, F] {} + new Coproduct[Traverse, F] {} - trait ProductTraverse[T[x[_]] <: Traverse[x], F[_]](using inst: K1.ProductInstances[T, F]) + trait Product[T[x[_]] <: Traverse[x], F[_]](using inst: K1.ProductInstances[T, F]) extends Traverse[F], - DerivedFunctor.GenericFunctor[T, F], + DerivedFunctor.Generic[T, F], DerivedFoldable.Product[T, F]: - override def traverse[G[_], A, B](fa: F[A])(f: A => G[B])(using G: Applicative[G]): G[F[B]] = + final override def traverse[G[_], A, B](fa: F[A])(f: A => G[B])(using G: Applicative[G]): G[F[B]] = val pure = [a] => (x: a) => G.pure(x) val map = [a, b] => (ga: G[a], f: a => b) => G.map(ga)(f) val ap = [a, b] => (gf: G[a => b], ga: G[a]) => G.ap(gf)(ga) inst.traverse[A, G, B](fa)(map)(pure)(ap)([f[_]] => (tf: T[f], fa: f[A]) => tf.traverse(fa)(f)) - trait CoproductTraverse[T[x[_]] <: Traverse[x], F[_]](using inst: K1.CoproductInstances[T, F]) + trait Coproduct[T[x[_]] <: Traverse[x], F[_]](using inst: K1.CoproductInstances[T, F]) extends Traverse[F], - DerivedFunctor.GenericFunctor[T, F], + DerivedFunctor.Generic[T, F], DerivedFoldable.Coproduct[T, F]: - override def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B]] = + final override def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B]] = inst.fold(fa)([f[_]] => (tf: T[f], fa: f[A]) => tf.traverse(fa)(f).asInstanceOf[G[F[B]]])