Skip to content

Commit

Permalink
Restrict strict derivation to product and coproduct
Browse files Browse the repository at this point in the history
  • Loading branch information
joroKr21 committed Jan 7, 2024
1 parent 93b2e92 commit e0a7872
Show file tree
Hide file tree
Showing 34 changed files with 166 additions and 240 deletions.
8 changes: 2 additions & 6 deletions core/src/main/scala-3/cats/derived/DerivedApplicative.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ object DerivedApplicative:

@nowarn("msg=unused import")
inline def strict[F[_]]: Applicative[F] =
import DerivedApplicative.given_DerivedApplicative_Const
import Strict.given
summonInline[DerivedApplicative[F]].instance

Expand All @@ -31,7 +30,8 @@ object DerivedApplicative:
def ap[A, B](ff: T)(fa: T): T = T.combine(ff, fa)

given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedApplicative[[x] =>> F[G[x]]] =
Strict.nested(using F.unify, G.unify)
new Derived.Lazy(() => F.unify.compose(using G.unify)) with Applicative[[x] =>> F[G[x]]]:
export delegate.*

given [F[_]](using inst: => K1.ProductInstances[Or, F]): DerivedApplicative[F] =
Strict.product(using inst.unify)
Expand All @@ -47,9 +47,5 @@ object DerivedApplicative:
inst.construct([f[_]] => (F: T[f]) => F.pure[A](x))

object Strict:
given nested[F[_], G[_]](using F: => Applicative[F], G: => Applicative[G]): DerivedApplicative[[x] =>> F[G[x]]] =
new Derived.Lazy(() => F.compose(G)) with Applicative[[x] =>> F[G[x]]]:
export delegate.*

given product[F[_]](using K1.ProductInstances[Applicative, F]): DerivedApplicative[F] =
new Product[Applicative, F] with DerivedApply.Product[Applicative, F] {}
8 changes: 2 additions & 6 deletions core/src/main/scala-3/cats/derived/DerivedApply.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ object DerivedApply:

@nowarn("msg=unused import")
inline def strict[F[_]]: Apply[F] =
import DerivedApply.given_DerivedApply_Const
import Strict.given
summonInline[DerivedApply[F]].instance

Expand All @@ -31,7 +30,8 @@ object DerivedApply:
def map[A, B](fa: T)(f: A => B): T = fa

given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedApply[[x] =>> F[G[x]]] =
Strict.nested(using F.unify, G.unify)
new Derived.Lazy(() => F.unify.compose(using G.unify)) with Apply[[x] =>> F[G[x]]]:
export delegate.*

given [F[_]](using inst: => K1.ProductInstances[Or, F]): DerivedApply[F] =
Strict.product(using inst.unify)
Expand All @@ -46,9 +46,5 @@ object DerivedApply:
inst.map2(ff, fa)([f[_]] => (F: T[f], ff: f[A => B], fa: f[A]) => F.ap(ff)(fa))

object Strict:
given nested[F[_], G[_]](using F: => Apply[F], G: => Apply[G]): DerivedApply[[x] =>> F[G[x]]] =
new Derived.Lazy(() => F.compose(G)) with Apply[[x] =>> F[G[x]]]:
export delegate.*

given product[F[_]](using K1.ProductInstances[Apply, F]): DerivedApply[F] =
new Product[Apply, F] {}
14 changes: 4 additions & 10 deletions core/src/main/scala-3/cats/derived/DerivedContravariant.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cats.derived

import cats.{Contravariant, Functor}
import cats.Contravariant
import shapeless3.deriving.{Const, K1}

import scala.annotation.*
Expand All @@ -23,15 +23,15 @@ object DerivedContravariant:

@nowarn("msg=unused import")
inline def strict[F[_]]: Contravariant[F] =
import DerivedContravariant.given_DerivedContravariant_Const
import Strict.given
summonInline[DerivedContravariant[F]].instance

given [T]: DerivedContravariant[Const[T]] = new Contravariant[Const[T]]:
def contramap[A, B](fa: T)(f: B => A): T = fa

given nested[F[_], G[_]](using F: DerivedFunctor.Or[F], G: => Or[G]): DerivedContravariant[[x] =>> F[G[x]]] =
Strict.nested(using F.unify, G.unify)
new Derived.Lazy(() => F.unify.composeContravariant(using G.unify)) with Contravariant[[x] =>> F[G[x]]]:
export delegate.*

given [F[_]](using inst: => K1.Instances[Or, F]): DerivedContravariant[F] =
generic(using inst.unify)
Expand All @@ -47,12 +47,6 @@ object DerivedContravariant:
inst.map(fa)([f[_]] => (T: T[f], fa: f[A]) => T.contramap(fa)(f))

object Strict:
given nested[F[_], G[_]](using F: Functor[F], G: => Contravariant[G]): DerivedContravariant[[x] =>> F[G[x]]] =
new Derived.Lazy(() => F.composeContravariant(G)) with Contravariant[[x] =>> F[G[x]]]:
export delegate.*

given product[F[_]](using K1.ProductInstances[Contravariant, F]): DerivedContravariant[F] =
generic

given product[F[_]](using K1.ProductInstances[Contravariant, F]): DerivedContravariant[F] = generic
given coproduct[F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedContravariant[F] =
generic(using inst.unify)
13 changes: 6 additions & 7 deletions core/src/main/scala-3/cats/derived/DerivedEmpty.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,15 @@ object DerivedEmpty:

@nowarn("msg=unused import")
inline def strict[A]: Empty[A] =
import DerivedEmpty.given
import Strict.product
import Strict.given
summonInline[DerivedEmpty[A]].instance

given product[A](using inst: K0.ProductInstances[Or, A]): DerivedEmpty[A] =
Strict.product(using inst.unify)

inline given coproduct[A](using gen: K0.CoproductGeneric[A]): DerivedEmpty[A] =
Empty(gen.withOnly[Or, A]([a <: A] => (A: Or[a]) => A.unify.empty))
given product[A](using inst: K0.ProductInstances[Or, A]): DerivedEmpty[A] = Strict.product(using inst.unify)
inline given coproduct[A](using gen: K0.CoproductGeneric[A]): DerivedEmpty[A] = Strict.coproduct

object Strict:
given product[A](using inst: K0.ProductInstances[Empty, A]): DerivedEmpty[A] =
Empty(inst.construct([a] => (A: Empty[a]) => A.empty))

inline given coproduct[A](using gen: K0.CoproductGeneric[A]): DerivedEmpty[A] =
Empty(gen.withOnly[Or, A]([a <: A] => (A: Or[a]) => A.unify.empty))
36 changes: 16 additions & 20 deletions core/src/main/scala-3/cats/derived/DerivedEmptyK.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cats.derived

import alleycats.{Empty, EmptyK, Pure}
import alleycats.{Empty, EmptyK}
import shapeless3.deriving.{Const, K1}

import scala.annotation.*
Expand All @@ -25,30 +25,31 @@ object DerivedEmptyK:

@nowarn("msg=unused import")
inline def strict[F[_]]: EmptyK[F] =
import DerivedEmptyK.given
import Strict.product
import Strict.given
summonInline[DerivedEmptyK[F]].instance

given [T](using T: Empty[T]): DerivedEmptyK[Const[T]] = new EmptyK[Const[T]]:
def empty[A]: T = T.empty

given nested[F[_], G[_]](using F: => Or[F]): DerivedEmptyK[[x] =>> F[G[x]]] =
Strict.nested(using F.unify)
new EmptyK[[x] =>> F[G[x]]]:
lazy val f = F.unify
def empty[A]: F[G[A]] = f.empty

given nested[F[_], G[_]](using
ev: NotGiven[Or[F]]
NotGiven[Or[F]]
)(using F: DerivedPure.Or[F], G: => Or[G]): DerivedEmptyK[[x] =>> F[G[x]]] =
Strict.nested(using ev.asInstanceOf)(using F.unify, G.unify)

given product[F[_]](using inst: K1.ProductInstances[Or, F]): DerivedEmptyK[F] =
Strict.product(using inst.unify)
new EmptyK[[x] =>> F[G[x]]]:
val f = F.unify
lazy val g = G.unify
def empty[A]: F[G[A]] = f.pure(g.empty)

inline given coproduct[F[_]](using gen: K1.CoproductGeneric[F]): DerivedEmptyK[F] =
gen.withOnly[Or, EmptyK[F]]([f[x] <: F[x]] => (F: Or[f]) => F.unify.asInstanceOf[EmptyK[F]])
given product[F[_]](using inst: K1.ProductInstances[Or, F]): DerivedEmptyK[F] = Strict.product(using inst.unify)
inline given coproduct[F[_]](using K1.CoproductGeneric[F]): DerivedEmptyK[F] = Strict.coproduct

@deprecated("Kept for binary compatibility", "3.2.0")
protected given [F[_], G[_]](using F: Or[F]): DerivedEmptyK[[x] =>> F[G[x]]] =
Strict.nested(using F.unify)
nested(using F)

@deprecated("Kept for binary compatibility", "3.2.0")
protected given [F[_], G[_]](using
Expand All @@ -57,13 +58,8 @@ object DerivedEmptyK:
nested(using ev)

object Strict:
given nested[F[_], G[_]](using F: => EmptyK[F]): DerivedEmptyK[[x] =>> F[G[x]]] = new EmptyK[[x] =>> F[G[x]]]:
def empty[A]: F[G[A]] = F.empty

given nested[F[_], G[_]](using
NotGiven[EmptyK[F]]
)(using F: Pure[F], G: => EmptyK[G]): DerivedEmptyK[[x] =>> F[G[x]]] = new EmptyK[[x] =>> F[G[x]]]:
def empty[A]: F[G[A]] = F.pure(G.empty)

given product[F[_]](using inst: K1.ProductInstances[EmptyK, F]): DerivedEmptyK[F] = new EmptyK[F]:
def empty[A]: F[A] = inst.construct([f[_]] => (F: EmptyK[f]) => F.empty[A])

inline given coproduct[F[_]](using gen: K1.CoproductGeneric[F]): DerivedEmptyK[F] =
gen.withOnly[Or, EmptyK[F]]([f[x] <: F[x]] => (F: Or[f]) => F.unify.asInstanceOf[EmptyK[F]])
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,8 +21,7 @@ object DerivedEq:

@nowarn("msg=unused import")
inline def strict[A]: Eq[A] =
import DerivedEq.given
import Strict.product
import Strict.given
summonInline[DerivedEq[A]].instance

given singleton[A <: Singleton: ValueOf]: DerivedEq[A] =
Expand All @@ -44,5 +43,6 @@ object DerivedEq:
[t] => (eqt: F[t], x: t, y: t) => eqt.eqv(x, y)

object Strict:
export DerivedEq.coproduct
given product[A](using K0.ProductInstances[Eq, A]): DerivedEq[A] =
new Product[Eq, A] {}
25 changes: 9 additions & 16 deletions core/src/main/scala-3/cats/derived/DerivedFoldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,23 @@ object DerivedFoldable:

@nowarn("msg=unused import")
inline def strict[F[_]]: Foldable[F] =
import DerivedFoldable.given
import Strict.{nested, product}
import Strict.given
summonInline[DerivedFoldable[F]].instance

given [T]: DerivedFoldable[Const[T]] = new Foldable[Const[T]]:
def foldLeft[A, B](fa: T, b: B)(f: (B, A) => B): B = b
def foldRight[A, B](fa: T, lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = lb

given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedFoldable[[x] =>> F[G[x]]] =
Strict.nested(using F.unify, G.unify)

given product[F[_]](using inst: K1.ProductInstances[Or, F]): DerivedFoldable[F] =
Strict.product(using inst.unify)
new Derived.Lazy(() => F.unify.compose(using G.unify)) with Foldable[[x] =>> F[G[x]]]:
export delegate.*

given [F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedFoldable[F] =
given K1.CoproductInstances[Foldable, F] = inst.unify
new Coproduct[Foldable, F] {}
given [F[_]](using inst: K1.ProductInstances[Or, F]): DerivedFoldable[F] = Strict.product(using inst.unify)
given [F[_]](using => K1.CoproductInstances[Or, F]): DerivedFoldable[F] = Strict.coproduct

@deprecated("Kept for binary compatibility", "3.2.0")
protected given [F[_]: Or, G[_]: Or]: DerivedFoldable[[x] =>> F[G[x]]] = nested

@deprecated("Kept for binary compatibility", "3.2.0")
protected given [F[_]](using K1.ProductInstances[Or, F]): DerivedFoldable[F] = product

trait Product[T[f[_]] <: Foldable[f], 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(fa)(b)([f[_]] => (b: B, F: T[f], fa: f[A]) => Continue(F.foldLeft(fa, b)(f)))
Expand All @@ -63,9 +56,9 @@ object DerivedFoldable:
inst.fold(fa)([f[_]] => (F: T[f], fa: f[A]) => Eval.defer(F.foldRight(fa, lb)(f)))

object Strict:
given nested[F[_], G[_]](using F: => Foldable[F], G: => Foldable[G]): DerivedFoldable[[x] =>> F[G[x]]] =
new Derived.Lazy(() => F.compose(G)) with Foldable[[x] =>> F[G[x]]]:
export delegate.*

given product[F[_]](using K1.ProductInstances[Foldable, F]): DerivedFoldable[F] =
new Product[Foldable, F] {}

given coproduct[F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedFoldable[F] =
given K1.CoproductInstances[Foldable, F] = inst.unify
new Coproduct[Foldable, F] {}
22 changes: 6 additions & 16 deletions core/src/main/scala-3/cats/derived/DerivedFunctor.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cats.derived

import cats.{Contravariant, Functor}
import cats.Functor
import shapeless3.deriving.{Const, K1}

import scala.annotation.*
Expand All @@ -24,21 +24,21 @@ object DerivedFunctor:

@nowarn("msg=unused import")
inline def strict[F[_]]: Functor[F] =
import DerivedFunctor.given_DerivedFunctor_Const
import Strict.given
summonInline[DerivedFunctor[F]].instance

given [T]: DerivedFunctor[Const[T]] = new Functor[Const[T]]:
def map[A, B](fa: T)(f: A => B): T = fa

given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedFunctor[[x] =>> F[G[x]]] =
Strict.nested(using F.unify, G.unify)
new Derived.Lazy(() => F.unify.compose(using G.unify)) with Functor[[x] =>> F[G[x]]]:
export delegate.*

given nested[F[_], G[_]](using
F: DerivedContravariant.Or[F],
G: DerivedContravariant.Or[G]
): DerivedFunctor[[x] =>> F[G[x]]] =
Strict.nested(using F.unify, G.unify)
F.unify.compose(using G.unify)

given [F[_]](using inst: => K1.Instances[Or, F]): DerivedFunctor[F] =
generic(using inst.unify)
Expand All @@ -62,15 +62,5 @@ object DerivedFunctor:
inst.map(fa)([f[_]] => (F: T[f], fa: f[A]) => F.map(fa)(f))

object Strict:
given nested[F[_], G[_]](using F: => Functor[F], G: => Functor[G]): DerivedFunctor[[x] =>> F[G[x]]] =
new Derived.Lazy(() => F.compose(G)) with Functor[[x] =>> F[G[x]]]:
export delegate.*

given nested[F[_]: Contravariant, G[_]: Contravariant]: DerivedFunctor[[x] =>> F[G[x]]] =
Contravariant[F].compose[G]

given product[F[_]](using K1.ProductInstances[Functor, F]): DerivedFunctor[F] =
generic

given coproduct[F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedFunctor[F] =
generic(using inst.unify)
given product[F[_]](using K1.ProductInstances[Functor, F]): DerivedFunctor[F] = generic
given coproduct[F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedFunctor[F] = generic(using inst.unify)
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 @@ -22,8 +22,7 @@ object DerivedHash:

@nowarn("msg=unused import")
inline def strict[A]: Hash[A] =
import DerivedHash.given
import Strict.product
import Strict.given
summonInline[DerivedHash[A]].instance

// These instances support singleton types unlike the instances in Cats' kernel.
Expand Down Expand Up @@ -66,5 +65,6 @@ object DerivedHash:
inst.fold[Int](x)([t] => (h: F[t], x: t) => h.hash(x))

object Strict:
export DerivedHash.coproduct
given product[A <: scala.Product](using K0.ProductInstances[Hash, A]): DerivedHash[A] =
new Product[Hash, A] {}
15 changes: 4 additions & 11 deletions core/src/main/scala-3/cats/derived/DerivedInvariant.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ object DerivedInvariant:

@nowarn("msg=unused import")
inline def strict[F[_]]: Invariant[F] =
import DerivedInvariant.given_DerivedInvariant_Const
import Strict.given
summonInline[DerivedInvariant[F]].instance

given [T]: DerivedInvariant[Const[T]] = new Invariant[Const[T]]:
def imap[A, B](fa: T)(f: A => B)(g: B => A): T = fa

given nested[F[_], G[_]](using F: => Or[F], G: => Or[G]): DerivedInvariant[[x] =>> F[G[x]]] =
Strict.nested(using F.unify, G.unify)
new Derived.Lazy(() => F.unify.compose(using G.unify)) with Invariant[[x] =>> F[G[x]]]:
export delegate.*

given [F[_]](using inst: => K1.Instances[Or, F]): DerivedInvariant[F] =
generic(using inst.unify)
Expand All @@ -47,12 +47,5 @@ object DerivedInvariant:
inst.map(fa)([f[_]] => (F: T[f], fa: f[A]) => F.imap(fa)(f)(g))

object Strict:
given nested[F[_], G[_]](using F: => Invariant[F], G: => Invariant[G]): DerivedInvariant[[x] =>> F[G[x]]] =
new Derived.Lazy(() => F.compose(G)) with Invariant[[x] =>> F[G[x]]]:
export delegate.*

given product[F[_]](using K1.ProductInstances[Invariant, F]): DerivedInvariant[F] =
generic

given coproduct[F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedInvariant[F] =
generic(using inst.unify)
given product[F[_]](using K1.ProductInstances[Invariant, F]): DerivedInvariant[F] = generic
given coproduct[F[_]](using inst: => K1.CoproductInstances[Or, F]): DerivedInvariant[F] = generic(using inst.unify)
Loading

0 comments on commit e0a7872

Please sign in to comment.