Skip to content

Commit

Permalink
Make derived methods final override (#395)
Browse files Browse the repository at this point in the history
  • Loading branch information
joroKr21 authored Oct 12, 2021
1 parent b2a1fef commit 873ae0d
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 87 deletions.
4 changes: 2 additions & 2 deletions core/src/main/scala-3/cats/derived/DerivedEq.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)
54 changes: 23 additions & 31 deletions core/src/main/scala-3/cats/derived/DerivedFoldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
6 changes: 3 additions & 3 deletions core/src/main/scala-3/cats/derived/DerivedFunctor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
4 changes: 2 additions & 2 deletions core/src/main/scala-3/cats/derived/DerivedHash.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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))
2 changes: 1 addition & 1 deletion core/src/main/scala-3/cats/derived/DerivedMonoid.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
22 changes: 10 additions & 12 deletions core/src/main/scala-3/cats/derived/DerivedNonEmptyTraverse.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
58 changes: 31 additions & 27 deletions core/src/main/scala-3/cats/derived/DerivedReducible.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)))
3 changes: 2 additions & 1 deletion core/src/main/scala-3/cats/derived/DerivedSemigroup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
16 changes: 8 additions & 8 deletions core/src/main/scala-3/cats/derived/DerivedTraverse.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]]])

0 comments on commit 873ae0d

Please sign in to comment.