-
-
Notifications
You must be signed in to change notification settings - Fork 67
Port Semigroupk/Monoidk to new scheme #472
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
Merged
joroKr21
merged 8 commits into
typelevel:dotty
from
TimWSpence:port-semigroupk-monoidk-to-new-scheme
May 24, 2022
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
6cca398
Port SemigroupK and MonoidK to new derivation scheme
TimWSpence 415df3c
WIP port of SemigroupK suite to scala 3
TimWSpence 7f74610
Nested derivations for SemigroupK
TimWSpence fe2b8b4
Priority for derived SemigroupK given instances
TimWSpence 84b0664
Port scala 2 MonoidK tests to scala 3
TimWSpence a1e9750
Various improvements
TimWSpence 819ab4f
Use inline in tests
TimWSpence fc2fced
SemigroupK/MonoidK test for derives syntax
TimWSpence File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package cats.derived | ||
|
|
||
| import cats.* | ||
| import shapeless3.deriving.{Const, K1} | ||
|
|
||
| import scala.annotation.implicitNotFound | ||
| import scala.compiletime.* | ||
| import scala.util.NotGiven | ||
|
|
||
| @implicitNotFound("""Could not derive an instance of MonoidK[F] where F = ${F}. | ||
| Make sure that F[_] satisfies one of the following conditions: | ||
| * it is a constant type [x] =>> T where T: Monoid | ||
| * it is a nested type [x] =>> G[H[x]] where G: MonoidK | ||
| * it is a nested type [x] =>> G[H[x]] where G: Applicative and H: MonoidK | ||
| * it is a generic case class where all fields have a MonoidK instance""") | ||
| type DerivedMonoidK[F[_]] = Derived[MonoidK[F]] | ||
| object DerivedMonoidK: | ||
| type Or[F[_]] = Derived.Or[MonoidK[F]] | ||
| inline def apply[F[_]]: MonoidK[F] = | ||
| import DerivedMonoidK.given | ||
| summonInline[DerivedMonoidK[F]].instance | ||
|
|
||
| given [T](using T: Monoid[T]): DerivedMonoidK[Const[T]] = new MonoidK[Const[T]]: | ||
| final override def empty[A]: Const[T][A] = T.empty | ||
|
|
||
| final override def combineK[A](x: Const[T][A], y: Const[T][A]) = T.combine(x, y) | ||
|
|
||
| given [F[_], G[_]](using F: Or[F]): DerivedMonoidK[[x] =>> F[G[x]]] = | ||
| F.unify.compose[G] | ||
|
joroKr21 marked this conversation as resolved.
|
||
|
|
||
| given [F[_], G[_]](using | ||
| N: NotGiven[Or[F]], | ||
| F0: DerivedApplicative.Or[F], | ||
| G0: Or[G] | ||
| ): DerivedMonoidK[[x] =>> F[G[x]]] = | ||
| new MonoidK[[x] =>> F[G[x]]]: | ||
| val F: Applicative[F] = F0.unify | ||
| val G: MonoidK[G] = G0.unify | ||
|
|
||
| final override def empty[A]: F[G[A]] = F.pure(G.empty[A]) | ||
|
|
||
| final override def combineK[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = F.map2(x, y)(G.combineK(_, _)) | ||
|
|
||
| given [F[_]](using inst: => K1.ProductInstances[Or, F]): DerivedMonoidK[F] = | ||
| given K1.ProductInstances[MonoidK, F] = inst.unify | ||
| new Product[MonoidK, F] {} | ||
|
|
||
| trait Product[T[x[_]] <: MonoidK[x], F[_]](using inst: K1.ProductInstances[T, F]) | ||
| extends MonoidK[F], | ||
| DerivedSemigroupK.Product[T, F]: | ||
| final override def empty[A]: F[A] = inst.construct([t[_]] => (emp: T[t]) => emp.empty[A]) | ||
39 changes: 39 additions & 0 deletions
39
core/src/main/scala-3/cats/derived/DerivedSemigroupK.scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package cats.derived | ||
|
|
||
| import cats.{Semigroup, SemigroupK} | ||
| import shapeless3.deriving.{Const, K1} | ||
|
|
||
| import scala.annotation.implicitNotFound | ||
| import scala.compiletime.* | ||
| import scala.util.NotGiven | ||
|
|
||
| @implicitNotFound("""Could not derive an instance of SemigroupK[F] where F = ${F}. | ||
| Make sure that F[_] satisfies one of the following conditions: | ||
| * it is a constant type [x] =>> T where T: Semigroup | ||
| * it is a nested type [x] =>> G[H[x]] where G: SemigroupK | ||
| * it is a nested type [x] =>> G[H[x]] where G: Apply and H: SemigroupK | ||
| * it is a generic case class where all fields have a SemigroupK instance""") | ||
| type DerivedSemigroupK[F[_]] = Derived[SemigroupK[F]] | ||
|
joroKr21 marked this conversation as resolved.
|
||
| object DerivedSemigroupK: | ||
| type Or[F[_]] = Derived.Or[SemigroupK[F]] | ||
| inline def apply[F[_]]: SemigroupK[F] = | ||
| import DerivedSemigroupK.given | ||
| summonInline[DerivedSemigroupK[F]].instance | ||
|
|
||
| given [T](using T: Semigroup[T]): DerivedSemigroupK[Const[T]] = new SemigroupK[Const[T]]: | ||
| final override def combineK[A](x: Const[T][A], y: Const[T][A]) = T.combine(x, y) | ||
|
|
||
| given [F[_], G[_]](using F: Or[F]): DerivedSemigroupK[[x] =>> F[G[x]]] = | ||
| F.unify.compose[G] | ||
|
|
||
| given [F[_], G[_]](using N: NotGiven[Or[F]], F: DerivedApply.Or[F], G: Or[G]): DerivedSemigroupK[[x] =>> F[G[x]]] = | ||
| new SemigroupK[[x] =>> F[G[x]]]: | ||
| final override def combineK[A](x: F[G[A]], y: F[G[A]]): F[G[A]] = F.unify.map2(x, y)(G.unify.combineK(_, _)) | ||
|
|
||
| given [F[_]](using inst: => K1.ProductInstances[Or, F]): DerivedSemigroupK[F] = | ||
| given K1.ProductInstances[SemigroupK, F] = inst.unify | ||
| new Product[SemigroupK, F] {} | ||
|
|
||
| trait Product[T[x[_]] <: SemigroupK[x], F[_]](using inst: K1.ProductInstances[T, F]) extends SemigroupK[F]: | ||
| final override def combineK[A](x: F[A], y: F[A]): F[A] = | ||
| inst.map2[A, A, A](x, y)([t[_]] => (smgrpk: T[t], x: t[A], y: t[A]) => smgrpk.combineK(x, y)) | ||
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| package cats.derived | ||
|
|
||
| import alleycats.* | ||
| import cats.* | ||
| import cats.derived.* | ||
| import cats.laws.discipline.{MonoidKTests, SerializableTests} | ||
| import org.scalacheck.Arbitrary | ||
| import scala.compiletime.* | ||
|
|
||
| class MonoidKSuite extends KittensSuite { | ||
| import MonoidKSuite.* | ||
| import TestDefns.* | ||
|
|
||
| inline def monoidKTests[F[_]]: MonoidKTests[F] = MonoidKTests[F](summonInline) | ||
|
|
||
| inline def testMonoidK(context: String): Unit = { | ||
| checkAll(s"$context.MonoidK[ComplexProduct]", monoidKTests[ComplexProduct].monoidK[Char]) | ||
| checkAll(s"$context.MonoidK[CaseClassWOption]", monoidKTests[CaseClassWOption].monoidK[Char]) | ||
| checkAll(s"$context.MonoidK[BoxMul]", monoidKTests[BoxMul].monoidK[Char]) | ||
| checkAll(s"$context.MonoidK is Serializable", SerializableTests.serializable(summonInline[MonoidK[ComplexProduct]])) | ||
|
|
||
| test(s"$context.MonoidK respects existing instances") { | ||
| val M = summonInline[MonoidK[BoxMul]] | ||
| assert(M.empty[Char] == Box(Mul[Char](1))) | ||
| assert(M.combineK(Box(Mul[Char](5)), Box(Mul[Char](5))) == Box(Mul[Char](25))) | ||
| } | ||
| } | ||
|
|
||
| { | ||
| import auto.monoidK.given | ||
| testMonoidK("auto") | ||
| } | ||
|
|
||
| { | ||
| import monInstances.given | ||
| testMonoidK("semi") | ||
| } | ||
| } | ||
|
|
||
| object MonoidKSuite { | ||
| import TestDefns._ | ||
|
|
||
| type BoxMul[A] = Box[Mul[A]] | ||
|
|
||
| object monInstances { | ||
| implicit val complexProduct: MonoidK[ComplexProduct] = semiauto.monoidK | ||
| implicit val caseClassWOption: MonoidK[CaseClassWOption] = semiauto.monoidK | ||
| implicit val boxMul: MonoidK[BoxMul] = semiauto.monoidK | ||
| } | ||
|
|
||
| final case class Mul[T](value: Int) | ||
| object Mul { | ||
|
|
||
| implicit def eqv[T]: Eq[Mul[T]] = Eq.by(_.value) | ||
|
|
||
| implicit def arbitrary[T]: Arbitrary[Mul[T]] = | ||
| Arbitrary(Arbitrary.arbitrary[Int].map(apply)) | ||
|
|
||
| implicit val monoidK: MonoidK[Mul] = new MonoidK[Mul] { | ||
| def empty[A] = Mul(1) | ||
| def combineK[A](x: Mul[A], y: Mul[A]) = Mul(x.value * y.value) | ||
| } | ||
| } | ||
|
|
||
| case class Simple[A](value1: List[A], value2: Set[A]) derives MonoidK | ||
| case class Recursive[A](first: List[A], rest: Recursive[A]) derives MonoidK | ||
| } |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| package cats.derived | ||
|
|
||
| import cats.* | ||
| import cats.laws.discipline.{SemigroupKTests, SerializableTests} | ||
| import org.scalacheck.Arbitrary | ||
| import scala.compiletime.* | ||
|
|
||
| class SemigroupKSuite extends KittensSuite { | ||
| import SemigroupKSuite.* | ||
| import TestDefns.* | ||
|
|
||
| inline def semigroupKTests[F[_]]: SemigroupKTests[F] = SemigroupKTests[F](summonInline) | ||
|
|
||
| inline def testSemigroupK(context: String): Unit = { | ||
| checkAll(s"$context.SemigroupK[ComplexProduct]", semigroupKTests[ComplexProduct].semigroupK[Char]) | ||
| checkAll(s"$context.SemigroupK[CaseClassWOption]", semigroupKTests[CaseClassWOption].semigroupK[Char]) | ||
| checkAll(s"$context.SemigroupK[BoxMul]", semigroupKTests[BoxMul].semigroupK[Char]) | ||
| checkAll( | ||
| s"$context.SemigroupK is Serializable", | ||
| SerializableTests.serializable(summonInline[SemigroupK[ComplexProduct]]) | ||
| ) | ||
|
|
||
| test(s"$context.SemigroupK respects existing instances") { | ||
| assert(summonInline[SemigroupK[BoxMul]].combineK(Box(Mul[Char](5)), Box(Mul[Char](5))) == Box(Mul[Char](25))) | ||
| } | ||
| } | ||
|
|
||
| locally { | ||
| import auto.semigroupK.given | ||
| testSemigroupK("auto") | ||
| } | ||
|
|
||
| locally { | ||
| import semiInstances.given | ||
| testSemigroupK("semiauto") | ||
| } | ||
| } | ||
|
|
||
| object SemigroupKSuite { | ||
| import TestDefns._ | ||
|
|
||
| type BoxMul[A] = Box[Mul[A]] | ||
|
|
||
| object semiInstances { | ||
| implicit val complexProduct: SemigroupK[ComplexProduct] = semiauto.semigroupK | ||
| implicit val caseClassWOption: SemigroupK[CaseClassWOption] = semiauto.semigroupK | ||
| implicit val boxMul: SemigroupK[BoxMul] = semiauto.semigroupK | ||
| } | ||
|
|
||
| final case class Mul[T](value: Int) | ||
| object Mul { | ||
|
|
||
| implicit def eqv[T]: Eq[Mul[T]] = Eq.by(_.value) | ||
|
|
||
| implicit def arbitrary[T]: Arbitrary[Mul[T]] = | ||
| Arbitrary(Arbitrary.arbitrary[Int].map(apply)) | ||
|
|
||
| implicit val semigroupK: SemigroupK[Mul] = new SemigroupK[Mul] { | ||
| def combineK[A](x: Mul[A], y: Mul[A]) = Mul(x.value * y.value) | ||
| } | ||
| } | ||
|
|
||
| case class Simple[A](value1: List[A], value2: Set[A]) derives SemigroupK | ||
| case class Recursive[A](first: List[A], rest: Recursive[A]) derives SemigroupK | ||
| } |
This file was deleted.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.