Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make derived methods final override #395

Merged
merged 1 commit into from
Oct 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]]])