From 483a31430c080b0821769a0a6d8124b1faec3e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Sat, 12 Nov 2022 23:33:52 +0100 Subject: [PATCH 001/123] Add FunctionN.applyN --- core/src/main/scala/cats/syntax/apply.scala | 2 +- project/Boilerplate.scala | 42 +++++++++++++++++-- .../test/scala/cats/tests/SyntaxSuite.scala | 18 ++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/core/src/main/scala/cats/syntax/apply.scala b/core/src/main/scala/cats/syntax/apply.scala index 868647b5dc..293f132479 100644 --- a/core/src/main/scala/cats/syntax/apply.scala +++ b/core/src/main/scala/cats/syntax/apply.scala @@ -22,7 +22,7 @@ package cats package syntax -trait ApplySyntax extends TupleSemigroupalSyntax { +trait ApplySyntax extends TupleSemigroupalSyntax with FunctionApplySyntax { implicit final def catsSyntaxApply[F[_], A](fa: F[A])(implicit F: Apply[F]): Apply.Ops[F, A] = new Apply.Ops[F, A] { type TypeClassType = Apply[F] diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index 996e385dab..fa6845c2da 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -32,6 +32,7 @@ object Boilerplate { GenParallelArityFunctions, GenParallelArityFunctions2, GenFoldableArityFunctions, + GenFunctionSyntax, GenTupleParallelSyntax, GenTupleShowInstances, GenTupleMonadInstances, @@ -594,7 +595,7 @@ object Boilerplate { | * @groupname FoldableSlidingN foldable arity | * @groupdesc FoldableSlidingN | * Group sequential elements into fixed sized tuples by passing a "sliding window" over them. - | * + | * | * A foldable with fewer elements than the window size will return an empty list unlike `Iterable#sliding(size: Int)`. | * Example: | * {{{ @@ -604,12 +605,12 @@ object Boilerplate { | * | * scala> Foldable[List].sliding4((1 to 10).toList) | * val res1: List[(Int, Int, Int, Int)] = List((1,2,3,4), (2,3,4,5), (3,4,5,6), (4,5,6,7), (5,6,7,8), (6,7,8,9), (7,8,9,10)) - | * + | * | * scala> Foldable[List].sliding4((1 to 2).toList) | * val res2: List[(Int, Int, Int, Int)] = List() | * | * }}} - | * + | * | * @groupprio FoldableSlidingN 999 | * | */ @@ -621,4 +622,39 @@ object Boilerplate { """ } } + + object GenFunctionSyntax extends Template { + def filename(root: File) = root / "cats" / "syntax" / "FunctionApplySyntax.scala" + + override def range = 2 to maxArity + + def content(tv: TemplateVals) = { + import tv._ + + val function = s"Function$arity[${`A..N`}, T]" + + val typedParams = synVals.zip(synTypes).map { case (v, t) => s"$v: F[$t]" }.mkString(", ") + + block""" + |package cats + |package syntax + | + |import cats.Functor + |import cats.Semigroupal + | + |trait FunctionApplySyntax { + | implicit def catsSyntaxFunction1Apply[T, A0](f: Function1[A0, T]): Function1ApplyOps[T, A0] = new Function1ApplyOps(f) + - implicit def catsSyntaxFunction${arity}Apply[T, ${`A..N`}](f: $function): Function${arity}ApplyOps[T, ${`A..N`}] = new Function${arity}ApplyOps(f) + |} + | + |private[syntax] final class Function1ApplyOps[T, A0](private val f: Function1[A0, T]) extends Serializable { + | def applyN[F[_]: Functor](a0: F[A0]): F[T] = Functor[F].map(a0)(f) + |} + | + -private[syntax] final class Function${arity}ApplyOps[T, ${`A..N`}](private val f: $function) extends Serializable { + - def applyN[F[_]: Functor: Semigroupal]($typedParams): F[T] = Semigroupal.map$arity(${`a..n`})(f) + -} + """ + } + } } diff --git a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala index 79abb123d9..b62fbc4e24 100644 --- a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala @@ -269,6 +269,24 @@ object SyntaxSuite { tfa.parFlatMap(mfone) } + def testApplyN[F[_]: Apply, A, B, C, T] = { + val fa = mock[F[A]] + val fb = mock[F[B]] + val fc = mock[F[C]] + + val fapply2 = mock[(A, B) => T] + + val result2 = fapply2.applyN(fa, fb) + + result2: F[T] + + val fapply3 = mock[(A, B, C) => T] + + val result3 = fapply3.applyN(fa, fb, fc) + + result3: F[T] + } + def testParallelBi[M[_], F[_], T[_, _]: Bitraverse, A, B, C, D](implicit P: Parallel.Aux[M, F]): Unit = { val tab = mock[T[A, B]] val f = mock[A => M[C]] From ca01c0e7dc37285c0bcd0b6b6f28bcb9254e9aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Sat, 12 Nov 2022 23:49:09 +0100 Subject: [PATCH 002/123] Add tupledF for good measure --- project/Boilerplate.scala | 2 ++ tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index fa6845c2da..e85c63f519 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -649,10 +649,12 @@ object Boilerplate { | |private[syntax] final class Function1ApplyOps[T, A0](private val f: Function1[A0, T]) extends Serializable { | def applyN[F[_]: Functor](a0: F[A0]): F[T] = Functor[F].map(a0)(f) + | def tupledF[F[_]: Functor](t: F[A0]): F[T] = Functor[F].map(t)(f) |} | -private[syntax] final class Function${arity}ApplyOps[T, ${`A..N`}](private val f: $function) extends Serializable { - def applyN[F[_]: Functor: Semigroupal]($typedParams): F[T] = Semigroupal.map$arity(${`a..n`})(f) + - def tupledF[F[_]: Functor](t: F[${`(A..N)`}]): F[T] = Functor[F].map(t)(f.tupled) -} """ } diff --git a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala index b62fbc4e24..2cdd239c93 100644 --- a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala @@ -285,6 +285,10 @@ object SyntaxSuite { val result3 = fapply3.applyN(fa, fb, fc) result3: F[T] + + val result3Tupled = fapply3.tupledF((fa, fb, fc).tupled) + + result3Tupled: F[T] } def testParallelBi[M[_], F[_], T[_, _]: Bitraverse, A, B, C, D](implicit P: Parallel.Aux[M, F]): Unit = { From eedb579116a60cf27ca0f0dc754658611d2af55c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Sat, 1 Jul 2023 03:41:04 +0200 Subject: [PATCH 003/123] Rename applyN to liftN, add compilation test for case 1 --- project/Boilerplate.scala | 4 ++-- .../src/test/scala/cats/tests/SyntaxSuite.scala | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index e85c63f519..e160c1b2ac 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -648,12 +648,12 @@ object Boilerplate { |} | |private[syntax] final class Function1ApplyOps[T, A0](private val f: Function1[A0, T]) extends Serializable { - | def applyN[F[_]: Functor](a0: F[A0]): F[T] = Functor[F].map(a0)(f) + | def liftN[F[_]: Functor](a0: F[A0]): F[T] = Functor[F].map(a0)(f) | def tupledF[F[_]: Functor](t: F[A0]): F[T] = Functor[F].map(t)(f) |} | -private[syntax] final class Function${arity}ApplyOps[T, ${`A..N`}](private val f: $function) extends Serializable { - - def applyN[F[_]: Functor: Semigroupal]($typedParams): F[T] = Semigroupal.map$arity(${`a..n`})(f) + - def liftN[F[_]: Functor: Semigroupal]($typedParams): F[T] = Semigroupal.map$arity(${`a..n`})(f) - def tupledF[F[_]: Functor](t: F[${`(A..N)`}]): F[T] = Functor[F].map(t)(f.tupled) -} """ diff --git a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala index 9ab10f47f2..ec937585d7 100644 --- a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala @@ -286,20 +286,26 @@ object SyntaxSuite { tfa.parFlatMap(mfone) } - def testApplyN[F[_]: Apply, A, B, C, T] = { + def testliftN[F[_]: Apply, A, B, C, T] = { val fa = mock[F[A]] val fb = mock[F[B]] val fc = mock[F[C]] + val fapply1 = mock[A => T] + + val result1 = fapply1.liftN(fa) + + result1: F[T] + val fapply2 = mock[(A, B) => T] - val result2 = fapply2.applyN(fa, fb) + val result2 = fapply2.liftN(fa, fb) result2: F[T] val fapply3 = mock[(A, B, C) => T] - val result3 = fapply3.applyN(fa, fb, fc) + val result3 = fapply3.liftN(fa, fb, fc) result3: F[T] From a92e469c181d63682a64fbd3bd1f087d473d312c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Sat, 1 Jul 2023 03:43:24 +0200 Subject: [PATCH 004/123] Add tupledF arity-1 test --- tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala index ec937585d7..9ad8bc7a69 100644 --- a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala @@ -309,6 +309,10 @@ object SyntaxSuite { result3: F[T] + val result1Tupled = fapply1.tupledF(fa) + + result1Tupled: F[T] + val result3Tupled = fapply3.tupledF((fa, fb, fc).tupled) result3Tupled: F[T] From f0d5605461233165959268ed1b025e0ce69a9055 Mon Sep 17 00:00:00 2001 From: Sisir Koppaka <74860378+ahoy196@users.noreply.github.com> Date: Sat, 21 Oct 2023 18:04:23 +0530 Subject: [PATCH 005/123] add Blue Insight Digital to ADOPTERS.md --- ADOPTERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ADOPTERS.md b/ADOPTERS.md index dcad9bef9a..e79f672fa6 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -16,6 +16,7 @@ And if you can, consider [supporting us](https://opencollective.com/typelevel). - [BabylonHealth](https://www.babylonhealth.com/) - [Banno Group inside of Jack Henry & Associates](https://banno.com/) - [Basefarm](https://basefarm.com/) +- [Blue Insight Digital](https://blueinsight.digital) - [buildo](https://buildo.io) - [BUX](https://getbux.com/) - [Chartboost](https://www.chartboost.com/) From 5857d385591aa1c1b9a7018dea5d49dbf525c26a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Thu, 4 Jan 2024 02:19:19 +0100 Subject: [PATCH 006/123] Add parLiftN --- project/Boilerplate.scala | 2 + .../test/scala/cats/tests/SyntaxSuite.scala | 42 ++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index e160c1b2ac..cc777af3cd 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -649,11 +649,13 @@ object Boilerplate { | |private[syntax] final class Function1ApplyOps[T, A0](private val f: Function1[A0, T]) extends Serializable { | def liftN[F[_]: Functor](a0: F[A0]): F[T] = Functor[F].map(a0)(f) + | def parLiftN[F[_]: Functor](a0: F[A0]): F[T] = Functor[F].map(a0)(f) | def tupledF[F[_]: Functor](t: F[A0]): F[T] = Functor[F].map(t)(f) |} | -private[syntax] final class Function${arity}ApplyOps[T, ${`A..N`}](private val f: $function) extends Serializable { - def liftN[F[_]: Functor: Semigroupal]($typedParams): F[T] = Semigroupal.map$arity(${`a..n`})(f) + - def parLiftN[F[_]: Parallel]($typedParams): F[T] = Parallel.parMap$arity(${`a..n`})(f) - def tupledF[F[_]: Functor](t: F[${`(A..N)`}]): F[T] = Functor[F].map(t)(f.tupled) -} """ diff --git a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala index a2150f1b98..5a4d405015 100644 --- a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala @@ -286,7 +286,7 @@ object SyntaxSuite { tfa.parFlatMap(mfone) } - def testliftN[F[_]: Apply, A, B, C, T] = { + def testLiftN[F[_]: Apply, A, B, C, T] = { val fa = mock[F[A]] val fb = mock[F[B]] val fc = mock[F[C]] @@ -308,12 +308,50 @@ object SyntaxSuite { val result3 = fapply3.liftN(fa, fb, fc) result3: F[T] + } + + def testParLiftN[F[_]: Parallel: Functor, A, B, C, T] = { + val fa = mock[F[A]] + val fb = mock[F[B]] + val fc = mock[F[C]] + + val fapply1 = mock[A => T] + + val result1 = fapply1.parLiftN(fa) + + result1: F[T] + + val fapply2 = mock[(A, B) => T] + + val result2 = fapply2.parLiftN(fa, fb) + + result2: F[T] + + val fapply3 = mock[(A, B, C) => T] + + val result3 = fapply3.parLiftN(fa, fb, fc) + + result3: F[T] + } + + def testTupledF[F[_]: Apply, A, B, C, T] = { + val fa = mock[F[A]] + val fab = mock[F[(A, B)]] + val fabc = mock[F[(A, B, C)]] + + val fapply1 = mock[A => T] + val fapply2 = mock[(A, B) => T] + val fapply3 = mock[(A, B, C) => T] val result1Tupled = fapply1.tupledF(fa) result1Tupled: F[T] - val result3Tupled = fapply3.tupledF((fa, fb, fc).tupled) + val result2Tupled = fapply2.tupledF(fab) + + result2Tupled: F[T] + + val result3Tupled = fapply3.tupledF(fabc) result3Tupled: F[T] } From 2010a2576fb2e63891cfde28ca9d05a9fa622744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Tue, 27 Feb 2024 12:25:48 +0100 Subject: [PATCH 007/123] Remove tupledF --- project/Boilerplate.scala | 2 -- .../test/scala/cats/tests/SyntaxSuite.scala | 22 ------------------- 2 files changed, 24 deletions(-) diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index cc777af3cd..2f95f75a16 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -650,13 +650,11 @@ object Boilerplate { |private[syntax] final class Function1ApplyOps[T, A0](private val f: Function1[A0, T]) extends Serializable { | def liftN[F[_]: Functor](a0: F[A0]): F[T] = Functor[F].map(a0)(f) | def parLiftN[F[_]: Functor](a0: F[A0]): F[T] = Functor[F].map(a0)(f) - | def tupledF[F[_]: Functor](t: F[A0]): F[T] = Functor[F].map(t)(f) |} | -private[syntax] final class Function${arity}ApplyOps[T, ${`A..N`}](private val f: $function) extends Serializable { - def liftN[F[_]: Functor: Semigroupal]($typedParams): F[T] = Semigroupal.map$arity(${`a..n`})(f) - def parLiftN[F[_]: Parallel]($typedParams): F[T] = Parallel.parMap$arity(${`a..n`})(f) - - def tupledF[F[_]: Functor](t: F[${`(A..N)`}]): F[T] = Functor[F].map(t)(f.tupled) -} """ } diff --git a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala index 5a4d405015..2f8e82e4bd 100644 --- a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala @@ -334,28 +334,6 @@ object SyntaxSuite { result3: F[T] } - def testTupledF[F[_]: Apply, A, B, C, T] = { - val fa = mock[F[A]] - val fab = mock[F[(A, B)]] - val fabc = mock[F[(A, B, C)]] - - val fapply1 = mock[A => T] - val fapply2 = mock[(A, B) => T] - val fapply3 = mock[(A, B, C) => T] - - val result1Tupled = fapply1.tupledF(fa) - - result1Tupled: F[T] - - val result2Tupled = fapply2.tupledF(fab) - - result2Tupled: F[T] - - val result3Tupled = fapply3.tupledF(fabc) - - result3Tupled: F[T] - } - def testParallelBi[M[_], F[_], T[_, _]: Bitraverse, A, B, C, D](implicit P: Parallel.Aux[M, F]): Unit = { val tab = mock[T[A, B]] val f = mock[A => M[C]] From 5c47f341f633a417ba1059092c8c5514ac283917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Tue, 27 Feb 2024 19:18:10 +0100 Subject: [PATCH 008/123] empty commit From ca6e66ecc80d3f1c897cd91991de09ca5ab7d83c Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 16:04:53 +0000 Subject: [PATCH 009/123] Update auxlib, clib, javalib, nativelib, ... to 0.5.2 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index a5b2fdf8bc..4ed4ae3b6f 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,5 +4,5 @@ addSbtPlugin("org.typelevel" % "sbt-typelevel-site" % sbtTypelevelVersion) addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") addSbtPlugin("com.github.tkawachi" % "sbt-doctest" % "0.10.0") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") -addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.1") +addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.2") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.12.0") From 4efe435ad41c5c5f7d9b0e80c54f6be2f7a8406e Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 00:15:34 +0000 Subject: [PATCH 010/123] Update auxlib, clib, javalib, nativelib, ... to 0.5.3 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 4ed4ae3b6f..5e0abb3d9b 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,5 +4,5 @@ addSbtPlugin("org.typelevel" % "sbt-typelevel-site" % sbtTypelevelVersion) addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") addSbtPlugin("com.github.tkawachi" % "sbt-doctest" % "0.10.0") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") -addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.2") +addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.3") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.12.0") From 096f4b3ef7c3fad1c323a39c8f7830140baa9f32 Mon Sep 17 00:00:00 2001 From: Tim Golding Date: Fri, 31 May 2024 18:28:26 +0100 Subject: [PATCH 011/123] Add distinctBy to NonEmptyCollection and all impls --- .../scala-2.13+/cats/data/NonEmptyLazyList.scala | 13 ++++++++----- core/src/main/scala/cats/data/NonEmptyChain.scala | 5 ++++- .../main/scala/cats/data/NonEmptyCollection.scala | 1 + core/src/main/scala/cats/data/NonEmptyList.scala | 11 +++++++---- core/src/main/scala/cats/data/NonEmptySeq.scala | 13 ++++++++----- core/src/main/scala/cats/data/NonEmptyVector.scala | 13 ++++++++----- .../cats/tests/NonEmptyLazyListSuite.scala | 7 +++++++ .../test/scala/cats/tests/NonEmptyChainSuite.scala | 6 ++++++ .../test/scala/cats/tests/NonEmptyListSuite.scala | 6 ++++++ .../test/scala/cats/tests/NonEmptySeqSuite.scala | 12 ++++++++++++ .../test/scala/cats/tests/NonEmptyVectorSuite.scala | 6 ++++++ 11 files changed, 73 insertions(+), 20 deletions(-) diff --git a/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala b/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala index 846b960ef1..08ee02dc40 100644 --- a/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala +++ b/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala @@ -345,14 +345,17 @@ class NonEmptyLazyListOps[A](private val value: NonEmptyLazyList[A]) /** * Remove duplicates. Duplicates are checked using `Order[_]` instance. */ - def distinct[AA >: A](implicit O: Order[AA]): NonEmptyLazyList[AA] = { - implicit val ord: Ordering[AA] = O.toOrdering + override def distinct[AA >: A](implicit O: Order[AA]): NonEmptyLazyList[AA] = distinctBy(identity[AA]) + + override def distinctBy[AA >: A, B](f: A => B)(implicit O: Order[B]): NonEmptyLazyList[AA] = { + implicit val ord: Ordering[B] = O.toOrdering val buf = LazyList.newBuilder[AA] - toLazyList.foldLeft(TreeSet.empty[AA]) { (elementsSoFar, a) => - if (elementsSoFar(a)) elementsSoFar + toLazyList.foldLeft(TreeSet.empty[B]) { (elementsSoFar, a) => + val b = f(a) + if (elementsSoFar(b)) elementsSoFar else { - buf += a; elementsSoFar + a + buf += a; elementsSoFar + b } } diff --git a/core/src/main/scala/cats/data/NonEmptyChain.scala b/core/src/main/scala/cats/data/NonEmptyChain.scala index 3742a92268..094d0efdd0 100644 --- a/core/src/main/scala/cats/data/NonEmptyChain.scala +++ b/core/src/main/scala/cats/data/NonEmptyChain.scala @@ -603,7 +603,10 @@ class NonEmptyChainOps[A](private val value: NonEmptyChain[A]) * Remove duplicates. Duplicates are checked using `Order[_]` instance. */ final def distinct[AA >: A](implicit O: Order[AA]): NonEmptyChain[AA] = - create(toChain.distinct[AA]) + distinctBy(identity[AA]) + + final def distinctBy[AA >: A, B](f: A => B)(implicit O: Order[B]): NonEmptyChain[AA] = + create(toChain.distinctBy[B](f)) final def sortBy[B](f: A => B)(implicit B: Order[B]): NonEmptyChain[A] = create(toChain.sortBy(f)) final def sorted[AA >: A](implicit AA: Order[AA]): NonEmptyChain[AA] = create(toChain.sorted[AA]) diff --git a/core/src/main/scala/cats/data/NonEmptyCollection.scala b/core/src/main/scala/cats/data/NonEmptyCollection.scala index 72c158a84e..b71660ef3c 100644 --- a/core/src/main/scala/cats/data/NonEmptyCollection.scala +++ b/core/src/main/scala/cats/data/NonEmptyCollection.scala @@ -52,6 +52,7 @@ private[cats] trait NonEmptyCollection[+A, U[+_], NE[+_]] extends Any { def zipWithIndex: NE[(A, Int)] def distinct[AA >: A](implicit O: Order[AA]): NE[AA] + def distinctBy[AA >: A, B](f: A => B)(implicit O: Order[B]): NE[AA] def sortBy[B](f: A => B)(implicit B: Order[B]): NE[A] def sorted[AA >: A](implicit AA: Order[AA]): NE[AA] def groupByNem[B](f: A => B)(implicit B: Order[B]): NonEmptyMap[B, NE[A]] diff --git a/core/src/main/scala/cats/data/NonEmptyList.scala b/core/src/main/scala/cats/data/NonEmptyList.scala index c2e86caa60..498ecb7ded 100644 --- a/core/src/main/scala/cats/data/NonEmptyList.scala +++ b/core/src/main/scala/cats/data/NonEmptyList.scala @@ -340,14 +340,17 @@ final case class NonEmptyList[+A](head: A, tail: List[A]) extends NonEmptyCollec /** * Remove duplicates. Duplicates are checked using `Order[_]` instance. */ - def distinct[AA >: A](implicit O: Order[AA]): NonEmptyList[AA] = { - implicit val ord: Ordering[AA] = O.toOrdering + override def distinct[AA >: A](implicit O: Order[AA]): NonEmptyList[AA] = distinctBy(identity[AA]) + + override def distinctBy[AA >: A, B](f: A => B)(implicit O: Order[B]): NonEmptyList[AA] = { + implicit val ord: Ordering[B] = O.toOrdering val buf = ListBuffer.empty[AA] - tail.foldLeft(TreeSet(head: AA)) { (elementsSoFar, b) => + tail.foldLeft(TreeSet(f(head): B)) { (elementsSoFar, a) => + val b = f(a) if (elementsSoFar(b)) elementsSoFar else { - buf += b; elementsSoFar + b + buf += a; elementsSoFar + b } } diff --git a/core/src/main/scala/cats/data/NonEmptySeq.scala b/core/src/main/scala/cats/data/NonEmptySeq.scala index f43ef75ac4..55632f9e34 100644 --- a/core/src/main/scala/cats/data/NonEmptySeq.scala +++ b/core/src/main/scala/cats/data/NonEmptySeq.scala @@ -236,14 +236,17 @@ final class NonEmptySeq[+A] private (val toSeq: Seq[A]) extends AnyVal with NonE /** * Remove duplicates. Duplicates are checked using `Order[_]` instance. */ - def distinct[AA >: A](implicit O: Order[AA]): NonEmptySeq[AA] = { - implicit val ord: Ordering[AA] = O.toOrdering + override def distinct[AA >: A](implicit O: Order[AA]): NonEmptySeq[AA] = distinctBy(identity[AA]) + + override def distinctBy[AA >: A, B](f: A => B)(implicit O: Order[B]): NonEmptySeq[AA] = { + implicit val ord: Ordering[B] = O.toOrdering val buf = Seq.newBuilder[AA] - tail.foldLeft(TreeSet(head: AA)) { (elementsSoFar, a) => - if (elementsSoFar(a)) elementsSoFar + tail.foldLeft(TreeSet(f(head): B)) { (elementsSoFar, a) => + val b = f(a) + if (elementsSoFar(b)) elementsSoFar else { - buf += a; elementsSoFar + a + buf += a; elementsSoFar + b } } diff --git a/core/src/main/scala/cats/data/NonEmptyVector.scala b/core/src/main/scala/cats/data/NonEmptyVector.scala index 583dd63612..d671f536fc 100644 --- a/core/src/main/scala/cats/data/NonEmptyVector.scala +++ b/core/src/main/scala/cats/data/NonEmptyVector.scala @@ -246,14 +246,17 @@ final class NonEmptyVector[+A] private (val toVector: Vector[A]) /** * Remove duplicates. Duplicates are checked using `Order[_]` instance. */ - def distinct[AA >: A](implicit O: Order[AA]): NonEmptyVector[AA] = { - implicit val ord: Ordering[AA] = O.toOrdering + override def distinct[AA >: A](implicit O: Order[AA]): NonEmptyVector[AA] = distinctBy(identity[AA]) + + override def distinctBy[AA >: A, B](f: A => B)(implicit O: Order[B]): NonEmptyVector[AA] = { + implicit val ord: Ordering[B] = O.toOrdering val buf = Vector.newBuilder[AA] - tail.foldLeft(TreeSet(head: AA)) { (elementsSoFar, a) => - if (elementsSoFar(a)) elementsSoFar + tail.foldLeft(TreeSet(f(head): B)) { (elementsSoFar, a) => + val b = f(a) + if (elementsSoFar(b)) elementsSoFar else { - buf += a; elementsSoFar + a + buf += a; elementsSoFar + b } } diff --git a/tests/shared/src/test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala b/tests/shared/src/test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala index a4cd1352e5..2ecd733d39 100644 --- a/tests/shared/src/test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala +++ b/tests/shared/src/test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala @@ -49,6 +49,7 @@ class NonEmptyLazyListSuite extends NonEmptyCollectionSuite[LazyList, NonEmptyLa checkAll(s"NonEmptyLazyList[Int]", HashTests[NonEmptyLazyList[Int]].hash) checkAll(s"Hash[NonEmptyLazyList[Int]]", SerializableTests.serializable(Hash[NonEmptyLazyList[Int]])) + checkAll("NonEmptyLazyList[Int]", NonEmptyAlternativeTests[NonEmptyLazyList].nonEmptyAlternative[Int, Int, Int]) checkAll("NonEmptyLazyList[Int]", NonEmptyAlternativeTests[NonEmptyLazyList].nonEmptyAlternative[Int, Int, Int]) checkAll("NonEmptyAlternative[NonEmptyLazyList]", SerializableTests.serializable(NonEmptyAlternative[NonEmptyLazyList]) @@ -175,6 +176,12 @@ class NonEmptyLazyListSuite extends NonEmptyCollectionSuite[LazyList, NonEmptyLa } } + test("NonEmptyLazyList#distinctBy is consistent with List#distinctBy") { + forAll { (ci: NonEmptyLazyList[Int], f: Int => String) => + assert(ci.distinctBy(f).toList === (ci.toList.distinctBy(f))) + } + } + test("NonEmptyLazyList#distinct is consistent with List#distinct") { forAll { (ci: NonEmptyLazyList[Int]) => assert(ci.distinct.toList === (ci.toList.distinct)) diff --git a/tests/shared/src/test/scala/cats/tests/NonEmptyChainSuite.scala b/tests/shared/src/test/scala/cats/tests/NonEmptyChainSuite.scala index d90eb488ce..5fd0fadf74 100644 --- a/tests/shared/src/test/scala/cats/tests/NonEmptyChainSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/NonEmptyChainSuite.scala @@ -203,6 +203,12 @@ class NonEmptyChainSuite extends NonEmptyCollectionSuite[Chain, NonEmptyChain, N } } + test("NonEmptyChain#distinctBy is consistent with List#distinctBy") { + forAll { (ci: NonEmptyChain[Int], f: Int => String) => + assert(ci.distinctBy(f).toList === (ci.toList.distinctBy(f))) + } + } + test("NonEmptyChain#distinct is consistent with List#distinct") { forAll { (ci: NonEmptyChain[Int]) => assert(ci.distinct.toList === (ci.toList.distinct)) diff --git a/tests/shared/src/test/scala/cats/tests/NonEmptyListSuite.scala b/tests/shared/src/test/scala/cats/tests/NonEmptyListSuite.scala index 2cda3b290e..a72995abf8 100644 --- a/tests/shared/src/test/scala/cats/tests/NonEmptyListSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/NonEmptyListSuite.scala @@ -296,6 +296,12 @@ class NonEmptyListSuite extends NonEmptyCollectionSuite[List, NonEmptyList, NonE } } + test("NonEmptyList#distinctBy is consistent with List#distinctBy") { + forAll { (nel: NonEmptyList[Int], f: Int => String) => + assert(nel.distinctBy(f).toList === (nel.toList.distinctBy(f))) + } + } + test("NonEmptyList#reverse is consistent with List#reverse") { forAll { (nel: NonEmptyList[Int]) => assert(nel.reverse.toList === (nel.toList.reverse)) diff --git a/tests/shared/src/test/scala/cats/tests/NonEmptySeqSuite.scala b/tests/shared/src/test/scala/cats/tests/NonEmptySeqSuite.scala index 8c59cc1cf6..36899298bc 100644 --- a/tests/shared/src/test/scala/cats/tests/NonEmptySeqSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/NonEmptySeqSuite.scala @@ -90,4 +90,16 @@ class NonEmptySeqSuite extends NonEmptyCollectionSuite[Seq, NonEmptySeq, NonEmpt assert(a.zip(b).toSeq === (a.toSeq.zip(b.toSeq))) } } + + test("NonEmptySeq#distinct is consistent with List#distinct") { + forAll { (nes: NonEmptySeq[Int]) => + assert(nes.distinct.toList === (nes.toList.distinct)) + } + } + + test("NonEmptySeq#distinctBy is consistent with List#distinctBy") { + forAll { (nes: NonEmptySeq[Int], f: Int => String) => + assert(nes.distinctBy(f).toList === (nes.toList.distinctBy(f))) + } + } } diff --git a/tests/shared/src/test/scala/cats/tests/NonEmptyVectorSuite.scala b/tests/shared/src/test/scala/cats/tests/NonEmptyVectorSuite.scala index 13b2ae8276..cc38da31b8 100644 --- a/tests/shared/src/test/scala/cats/tests/NonEmptyVectorSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/NonEmptyVectorSuite.scala @@ -359,6 +359,12 @@ class NonEmptyVectorSuite extends NonEmptyCollectionSuite[Vector, NonEmptyVector assert(compileErrors("val bad: NonEmptyVector[Int] = NonEmptyVector(Vector.empty[Int])").nonEmpty) } + test("NonEmptyVector#distinctBy is consistent with Vector#distinctBy") { + forAll { (nonEmptyVector: NonEmptyVector[Int], f: Int => String) => + assert(nonEmptyVector.distinctBy(f).toVector === (nonEmptyVector.toVector.distinctBy(f))) + } + } + test("NonEmptyVector#distinct is consistent with Vector#distinct") { forAll { (nonEmptyVector: NonEmptyVector[Int]) => assert(nonEmptyVector.distinct.toVector === (nonEmptyVector.toVector.distinct)) From a39d75fca080a30510aae8e989ff19b0d4649daf Mon Sep 17 00:00:00 2001 From: Tim Golding Date: Wed, 5 Jun 2024 11:32:57 +0100 Subject: [PATCH 012/123] Simplify type signature of distinctBy --- core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala | 4 ++-- core/src/main/scala/cats/data/NonEmptyChain.scala | 2 +- core/src/main/scala/cats/data/NonEmptyCollection.scala | 2 +- core/src/main/scala/cats/data/NonEmptyList.scala | 4 ++-- core/src/main/scala/cats/data/NonEmptySeq.scala | 4 ++-- core/src/main/scala/cats/data/NonEmptyVector.scala | 4 ++-- .../test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala | 1 - 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala b/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala index 08ee02dc40..6faf08c5b6 100644 --- a/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala +++ b/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala @@ -347,10 +347,10 @@ class NonEmptyLazyListOps[A](private val value: NonEmptyLazyList[A]) */ override def distinct[AA >: A](implicit O: Order[AA]): NonEmptyLazyList[AA] = distinctBy(identity[AA]) - override def distinctBy[AA >: A, B](f: A => B)(implicit O: Order[B]): NonEmptyLazyList[AA] = { + override def distinctBy[B](f: A => B)(implicit O: Order[B]): NonEmptyLazyList[A] = { implicit val ord: Ordering[B] = O.toOrdering - val buf = LazyList.newBuilder[AA] + val buf = LazyList.newBuilder[A] toLazyList.foldLeft(TreeSet.empty[B]) { (elementsSoFar, a) => val b = f(a) if (elementsSoFar(b)) elementsSoFar diff --git a/core/src/main/scala/cats/data/NonEmptyChain.scala b/core/src/main/scala/cats/data/NonEmptyChain.scala index 094d0efdd0..3ab876bc43 100644 --- a/core/src/main/scala/cats/data/NonEmptyChain.scala +++ b/core/src/main/scala/cats/data/NonEmptyChain.scala @@ -605,7 +605,7 @@ class NonEmptyChainOps[A](private val value: NonEmptyChain[A]) final def distinct[AA >: A](implicit O: Order[AA]): NonEmptyChain[AA] = distinctBy(identity[AA]) - final def distinctBy[AA >: A, B](f: A => B)(implicit O: Order[B]): NonEmptyChain[AA] = + final def distinctBy[B](f: A => B)(implicit O: Order[B]): NonEmptyChain[A] = create(toChain.distinctBy[B](f)) final def sortBy[B](f: A => B)(implicit B: Order[B]): NonEmptyChain[A] = create(toChain.sortBy(f)) diff --git a/core/src/main/scala/cats/data/NonEmptyCollection.scala b/core/src/main/scala/cats/data/NonEmptyCollection.scala index b71660ef3c..6debb0e055 100644 --- a/core/src/main/scala/cats/data/NonEmptyCollection.scala +++ b/core/src/main/scala/cats/data/NonEmptyCollection.scala @@ -52,7 +52,7 @@ private[cats] trait NonEmptyCollection[+A, U[+_], NE[+_]] extends Any { def zipWithIndex: NE[(A, Int)] def distinct[AA >: A](implicit O: Order[AA]): NE[AA] - def distinctBy[AA >: A, B](f: A => B)(implicit O: Order[B]): NE[AA] + def distinctBy[B](f: A => B)(implicit O: Order[B]): NE[A] def sortBy[B](f: A => B)(implicit B: Order[B]): NE[A] def sorted[AA >: A](implicit AA: Order[AA]): NE[AA] def groupByNem[B](f: A => B)(implicit B: Order[B]): NonEmptyMap[B, NE[A]] diff --git a/core/src/main/scala/cats/data/NonEmptyList.scala b/core/src/main/scala/cats/data/NonEmptyList.scala index 498ecb7ded..b86ac76ec9 100644 --- a/core/src/main/scala/cats/data/NonEmptyList.scala +++ b/core/src/main/scala/cats/data/NonEmptyList.scala @@ -342,10 +342,10 @@ final case class NonEmptyList[+A](head: A, tail: List[A]) extends NonEmptyCollec */ override def distinct[AA >: A](implicit O: Order[AA]): NonEmptyList[AA] = distinctBy(identity[AA]) - override def distinctBy[AA >: A, B](f: A => B)(implicit O: Order[B]): NonEmptyList[AA] = { + override def distinctBy[B](f: A => B)(implicit O: Order[B]): NonEmptyList[A] = { implicit val ord: Ordering[B] = O.toOrdering - val buf = ListBuffer.empty[AA] + val buf = ListBuffer.empty[A] tail.foldLeft(TreeSet(f(head): B)) { (elementsSoFar, a) => val b = f(a) if (elementsSoFar(b)) elementsSoFar diff --git a/core/src/main/scala/cats/data/NonEmptySeq.scala b/core/src/main/scala/cats/data/NonEmptySeq.scala index 55632f9e34..65d76440fb 100644 --- a/core/src/main/scala/cats/data/NonEmptySeq.scala +++ b/core/src/main/scala/cats/data/NonEmptySeq.scala @@ -238,10 +238,10 @@ final class NonEmptySeq[+A] private (val toSeq: Seq[A]) extends AnyVal with NonE */ override def distinct[AA >: A](implicit O: Order[AA]): NonEmptySeq[AA] = distinctBy(identity[AA]) - override def distinctBy[AA >: A, B](f: A => B)(implicit O: Order[B]): NonEmptySeq[AA] = { + override def distinctBy[B](f: A => B)(implicit O: Order[B]): NonEmptySeq[A] = { implicit val ord: Ordering[B] = O.toOrdering - val buf = Seq.newBuilder[AA] + val buf = Seq.newBuilder[A] tail.foldLeft(TreeSet(f(head): B)) { (elementsSoFar, a) => val b = f(a) if (elementsSoFar(b)) elementsSoFar diff --git a/core/src/main/scala/cats/data/NonEmptyVector.scala b/core/src/main/scala/cats/data/NonEmptyVector.scala index d671f536fc..b2cca67fe1 100644 --- a/core/src/main/scala/cats/data/NonEmptyVector.scala +++ b/core/src/main/scala/cats/data/NonEmptyVector.scala @@ -248,10 +248,10 @@ final class NonEmptyVector[+A] private (val toVector: Vector[A]) */ override def distinct[AA >: A](implicit O: Order[AA]): NonEmptyVector[AA] = distinctBy(identity[AA]) - override def distinctBy[AA >: A, B](f: A => B)(implicit O: Order[B]): NonEmptyVector[AA] = { + override def distinctBy[B](f: A => B)(implicit O: Order[B]): NonEmptyVector[A] = { implicit val ord: Ordering[B] = O.toOrdering - val buf = Vector.newBuilder[AA] + val buf = Vector.newBuilder[A] tail.foldLeft(TreeSet(f(head): B)) { (elementsSoFar, a) => val b = f(a) if (elementsSoFar(b)) elementsSoFar diff --git a/tests/shared/src/test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala b/tests/shared/src/test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala index 2ecd733d39..6043bb870e 100644 --- a/tests/shared/src/test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala +++ b/tests/shared/src/test/scala-2.13+/cats/tests/NonEmptyLazyListSuite.scala @@ -49,7 +49,6 @@ class NonEmptyLazyListSuite extends NonEmptyCollectionSuite[LazyList, NonEmptyLa checkAll(s"NonEmptyLazyList[Int]", HashTests[NonEmptyLazyList[Int]].hash) checkAll(s"Hash[NonEmptyLazyList[Int]]", SerializableTests.serializable(Hash[NonEmptyLazyList[Int]])) - checkAll("NonEmptyLazyList[Int]", NonEmptyAlternativeTests[NonEmptyLazyList].nonEmptyAlternative[Int, Int, Int]) checkAll("NonEmptyLazyList[Int]", NonEmptyAlternativeTests[NonEmptyLazyList].nonEmptyAlternative[Int, Int, Int]) checkAll("NonEmptyAlternative[NonEmptyLazyList]", SerializableTests.serializable(NonEmptyAlternative[NonEmptyLazyList]) From 431e1cd34af9fa0a58eeb60cdfeeb5d5e2164052 Mon Sep 17 00:00:00 2001 From: David Strawn Date: Thu, 6 Jun 2024 12:40:30 -0500 Subject: [PATCH 013/123] Add Hash and Order Instances for NonEmptyVector --- .../main/scala/cats/data/NonEmptyVector.scala | 23 +++++++++++++++++-- .../cats/tests/NonEmptyVectorSuite.scala | 4 ++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/data/NonEmptyVector.scala b/core/src/main/scala/cats/data/NonEmptyVector.scala index b2cca67fe1..38d0824287 100644 --- a/core/src/main/scala/cats/data/NonEmptyVector.scala +++ b/core/src/main/scala/cats/data/NonEmptyVector.scala @@ -387,7 +387,7 @@ final class NonEmptyVector[+A] private (val toVector: Vector[A]) } @suppressUnusedImportWarningForScalaVersionSpecific -sealed abstract private[data] class NonEmptyVectorInstances { +sealed abstract private[data] class NonEmptyVectorInstances extends NonEmptyVectorInstances0 { @deprecated( "maintained for the sake of binary compatibility only - use catsDataInstancesForNonEmptyChainBinCompat1 instead", @@ -564,7 +564,11 @@ sealed abstract private[data] class NonEmptyVectorInstances { NonEmptyVector.fromVectorUnsafe(Align[Vector].alignWith(fa.toVector, fb.toVector)(f)) } - implicit def catsDataEqForNonEmptyVector[A: Eq]: Eq[NonEmptyVector[A]] = _ === _ + implicit def catsDataOrderForNonEmptyVector[A: Order]: Order[NonEmptyVector[A]] = + new Order[NonEmptyVector[A]] { + override def compare(x: NonEmptyVector[A], y: NonEmptyVector[A]): Int = + Order[Vector[A]].compare(x.toVector, y.toVector) + } implicit def catsDataShowForNonEmptyVector[A: Show]: Show[NonEmptyVector[A]] = _.show @@ -589,6 +593,21 @@ sealed abstract private[data] class NonEmptyVectorInstances { } +sealed abstract private[data] class NonEmptyVectorInstances0 extends NonEmptyVectorInstances1 { + implicit def catsDataHashForNonEmptyVector[A: Hash]: Hash[NonEmptyVector[A]] = + new Hash[NonEmptyVector[A]] { + override def hash(x: NonEmptyVector[A]): Int = + Hash[Vector[A]].hash(x.toVector) + + override def eqv(x: NonEmptyVector[A], y: NonEmptyVector[A]): Boolean = + Hash[Vector[A]].eqv(x.toVector, y.toVector) + } +} + +sealed abstract private[data] class NonEmptyVectorInstances1 { + implicit def catsDataEqForNonEmptyVector[A: Eq]: Eq[NonEmptyVector[A]] = _ === _ +} + object NonEmptyVector extends NonEmptyVectorInstances with Serializable { def apply[A](head: A, tail: Vector[A]): NonEmptyVector[A] = diff --git a/tests/shared/src/test/scala/cats/tests/NonEmptyVectorSuite.scala b/tests/shared/src/test/scala/cats/tests/NonEmptyVectorSuite.scala index cc38da31b8..1e36e10115 100644 --- a/tests/shared/src/test/scala/cats/tests/NonEmptyVectorSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/NonEmptyVectorSuite.scala @@ -26,6 +26,8 @@ import cats.data.NonEmptyVector import cats.data.NonEmptyVector.ZipNonEmptyVector import cats.kernel.instances.order.catsKernelOrderingForOrder import cats.kernel.laws.discipline.EqTests +import cats.kernel.laws.discipline.HashTests +import cats.kernel.laws.discipline.OrderTests import cats.kernel.laws.discipline.SemigroupTests import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ @@ -49,6 +51,8 @@ class NonEmptyVectorSuite extends NonEmptyCollectionSuite[Vector, NonEmptyVector Parameters.default.withMinSuccessfulTests(20).withMaxSize(Parameters.default.minSize + 5) checkAll("NonEmptyVector[Int]", EqTests[NonEmptyVector[Int]].eqv) + checkAll("NonEmptyVector[Int]", OrderTests[NonEmptyVector[Int]].order) + checkAll("NonEmptyVector[Int]", HashTests[NonEmptyVector[Int]].hash) checkAll("NonEmptyVector[Int] with Option", NonEmptyTraverseTests[NonEmptyVector].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option] From bdfafe87144e5fc02dbd19549a3df030e3704554 Mon Sep 17 00:00:00 2001 From: David Strawn Date: Thu, 6 Jun 2024 15:49:34 -0500 Subject: [PATCH 014/123] Add PartialOrder for NonEmptyVector --- core/src/main/scala/cats/data/NonEmptyVector.scala | 7 ++++++- .../src/test/scala/cats/tests/NonEmptyVectorSuite.scala | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/data/NonEmptyVector.scala b/core/src/main/scala/cats/data/NonEmptyVector.scala index 38d0824287..65225ec534 100644 --- a/core/src/main/scala/cats/data/NonEmptyVector.scala +++ b/core/src/main/scala/cats/data/NonEmptyVector.scala @@ -604,7 +604,12 @@ sealed abstract private[data] class NonEmptyVectorInstances0 extends NonEmptyVec } } -sealed abstract private[data] class NonEmptyVectorInstances1 { +sealed abstract private[data] class NonEmptyVectorInstances1 extends NonEmptyVectorInstances2 { + implicit def catsDataPartialOrderForNonEmptyVector[A: PartialOrder]: PartialOrder[NonEmptyVector[A]] = + PartialOrder.by[NonEmptyVector[A], Vector[A]](_.toVector) +} + +sealed abstract private[data] class NonEmptyVectorInstances2 { implicit def catsDataEqForNonEmptyVector[A: Eq]: Eq[NonEmptyVector[A]] = _ === _ } diff --git a/tests/shared/src/test/scala/cats/tests/NonEmptyVectorSuite.scala b/tests/shared/src/test/scala/cats/tests/NonEmptyVectorSuite.scala index 1e36e10115..0656ca9d94 100644 --- a/tests/shared/src/test/scala/cats/tests/NonEmptyVectorSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/NonEmptyVectorSuite.scala @@ -29,6 +29,7 @@ import cats.kernel.laws.discipline.EqTests import cats.kernel.laws.discipline.HashTests import cats.kernel.laws.discipline.OrderTests import cats.kernel.laws.discipline.SemigroupTests +import cats.kernel.laws.discipline.PartialOrderTests import cats.laws.discipline._ import cats.laws.discipline.arbitrary._ import cats.platform.Platform @@ -51,8 +52,9 @@ class NonEmptyVectorSuite extends NonEmptyCollectionSuite[Vector, NonEmptyVector Parameters.default.withMinSuccessfulTests(20).withMaxSize(Parameters.default.minSize + 5) checkAll("NonEmptyVector[Int]", EqTests[NonEmptyVector[Int]].eqv) - checkAll("NonEmptyVector[Int]", OrderTests[NonEmptyVector[Int]].order) checkAll("NonEmptyVector[Int]", HashTests[NonEmptyVector[Int]].hash) + checkAll("NonEmptyVector[Int]", OrderTests[NonEmptyVector[Int]].order) + checkAll("NonEmptyVector[Int]", PartialOrderTests[NonEmptyVector[Int]].partialOrder) checkAll("NonEmptyVector[Int] with Option", NonEmptyTraverseTests[NonEmptyVector].nonEmptyTraverse[Option, Int, Int, Int, Int, Option, Option] From 76886800a44ace49e850dd06054fbfc00ed1e79e Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 8 Jun 2024 11:59:48 -0700 Subject: [PATCH 015/123] correct & add documentation links --- core/src/main/scala/cats/package.scala | 50 ++++++++++++++------------ 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/core/src/main/scala/cats/package.scala b/core/src/main/scala/cats/package.scala index 2d442c8030..491926f25f 100644 --- a/core/src/main/scala/cats/package.scala +++ b/core/src/main/scala/cats/package.scala @@ -26,32 +26,36 @@ import cats.data.Ior * The `cats` root package contains all the trait signatures of most Scala type classes. * * Cats type classes are implemented using the approach from the - * [[https://ropas.snu.ac.kr/~bruno/papers/TypeClasses.pdf Type classes as objects and implicits]] article. + * "[[https://i.cs.hku.hk/~bruno/papers/TypeClasses.pdf Type classes as objects and implicits]]" article. * - * For each type class, `cats` provides three pieces: - * - Its '''signature''': a trait that is polymorphic on a type parameter. - * Type class traits inherit from other type classes to indicate that any implementation of the lower type class (e.g. `Applicative`) - * can also serve as an instance for the higher type class (e.g. `Functor`). - * - Type class ''''instances''', which are classes and objects that implement one or more type class signatures for some specific types. - * Type class instances for several data types from the Java or Scala standard libraries are declared in the subpackage `cats.instances`. - * - '''Syntax extensions''', each of which provides the methods of the type class defines as extension methods - * (which in Scala 2 are encoded as implicit classes) for values of any type `F`; given that an instance of the type class - * for the receiver type (`this`) is in the implicit scope. - * Syntax extensions are declared in the `cats.syntax` package. - * - A set of '''laws''', that are also generic on the type of the class, and are only defined on the operations of the type class. - * The purpose of these laws is to declare some algebraic relations (equations) between Scala expressions involving the operations - * of the type class, and test (but not verify) that implemented instances satisfy those equations. - * Laws are defined in the `cats-laws` package. + * For each type class, `cats` provides four pieces: + * - Its '''signature''': a trait that is polymorphic on a type parameter. + * Type class traits inherit from other type classes to indicate that any implementation of the lower type class + * (e.g. [[Applicative `Applicative`]]) + * can also serve as an instance for the higher type class (e.g. [[Functor `Functor`]]). + * - Type class '''instances''', which are classes and objects that implement one or more type class signatures for some specific types. + * Type class instances for several data types from the Java or Scala standard libraries are declared + * in the subpackage [[cats.instances `cats.instances`]]. + * - '''Syntax extensions''', each of which provides the methods of the type class defined as extension methods + * (which in Scala 2 are encoded as implicit classes) for values of any type `F`; given that an instance of the type class + * for the receiver type (`this`) is in the implicit scope. + * Syntax extensions are declared in the [[cats.syntax `cats.syntax`]] package. + * - A set of '''laws''', that are also generic on the type of the class, and are only defined on the operations of the type class. + * The purpose of these laws is to declare some algebraic relations (equations) between Scala expressions involving the operations + * of the type class, and test (but not verify) that implemented instances satisfy those equations. + * Laws are defined in the [[cats.laws `cats.laws`]] package. * * Although most of cats type classes are declared in this package, some are declared in other packages: - * - type classes that operate on base types (kind `*`), and their implementations for standard library types, - * are contained in `cats.kernel`, which is a different SBT project. However, they are re-exported from this package. - * - type classes of kind `F[_, _]`, such as [[cats.arrow.Profunctor]]" or [[cats.arrow.Arrow]], which are relevant for - * Functional Reactive Programming or optics, are declared in the `cats.arrow` package. - * - Also, those type classes that abstract over (pure or impure) functional runtime effects are declared - * in the [[https://typelevel.org/cats-effect/ cats-effect library]]. - * - Some type classes for which no laws can be provided are left out of the main road, in a small and dirty alley. - * These are the `alleycats`. + * - type classes that operate on base types (kind `*`), and their implementations for standard library types, + * are contained in [[cats.kernel `cats.kernel`]], which is a different SBT project. However, they are re-exported from this package. + * - type classes of kind `F[_, _]`, + * such as [[cats.arrow.Profunctor `cats.arrow.Profunctor`]] or [[cats.arrow.Arrow `cats.arrow.Arrow`]], + * which are relevant for + * Functional Reactive Programming or optics, are declared in the [[cats.arrow `cats.arrow`]] package. + * - Also, those type classes that abstract over (pure or impure) functional runtime effects are declared + * in the [[https://typelevel.org/cats-effect/ cats-effect library]]. + * - Some type classes for which no laws can be provided are left out of the main road, in a small and dirty alley. + * These are the [[alleycats `alleycats`]]. */ package object cats { From 531ed53b43e675535b951babc62c2cfe459ecfde Mon Sep 17 00:00:00 2001 From: Mike Date: Sun, 9 Jun 2024 16:44:08 -0700 Subject: [PATCH 016/123] clean up punctuation in `MonadError` use case --- docs/typeclasses/applicativemonaderror.md | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/docs/typeclasses/applicativemonaderror.md b/docs/typeclasses/applicativemonaderror.md index 3a8055aad4..be246a1cd3 100644 --- a/docs/typeclasses/applicativemonaderror.md +++ b/docs/typeclasses/applicativemonaderror.md @@ -261,16 +261,16 @@ With the methods that we will compose in place let's create a method that will compose the above methods using a for comprehension which interprets to a `flatMap`-`map` combination. -`getTemperatureFromByCoordinates` parameterized type -`[F[_]:MonadError[*[_], String]` injects `F[_]` into `MonadError[*[_], String]` +`getTemperatureByCoordinates`'s parameterized type +`[F[_]:MonadError[*[_], String]` injects `F[_]` into `MonadError[*[_], String]`; thus if the "error type" you wish to use is `Either[String, *]`, the `Either` would be placed in the hole of `MonadError`, in this case, `MonadError[Either[String, *], String]` -`getTemperatureFromByCoordinates` accepts a `Tuple2` of `Int` and `Int`, and we -return `F` which represents our `MonadError` which can be a type like `Either` or -`Validated`. In the method, since either `getCityClosestToCoordinate` and -`getTemperatureByCity` both return potential error types and they are monadic we can +`getTemperatureByCoordinates` accepts a `Tuple2` of `Int` and `Int` and +returns `F`, which represents our `MonadError`, which can be a type like `Either` or +`Validated`. In the method, since `getCityClosestToCoordinate` and +`getTemperatureByCity` both return potential error types and they are monadic, we can compose them with a for comprehension. ```scala mdoc:silent @@ -280,17 +280,14 @@ def getTemperatureByCoordinates[F[_]: MonadError[*[_], String]](x: (Int, Int)): } ``` -Invoking `getTemperatureByCoordinates` we can call it with the following sample, -which will return `78`. - -NOTE: infix `->` creates a `Tuple2`. `1 -> "Bob"` is the same as `(1, "Bob")` +We can call `getTemperatureByCoordinates` with the following sample, which will return `78`. ```scala mdoc:silent type MyEither[A] = Either[String, A] -getTemperatureByCoordinates[MyEither](44 -> 93) +getTemperatureByCoordinates[MyEither]((44, 93)) ``` -With TypeLevel Cats, how you structure your methods is up to you, if you wanted to +With TypeLevel Cats, how you structure your methods is up to you: if you wanted to create `getTemperatureByCoordinates` without a Scala [context bound](https://docs.scala-lang.org/tutorials/FAQ/context-bounds.html) for `MonadError`, but create an `implicit` parameter for your `MonadError` you can have access to some @@ -302,7 +299,7 @@ specialized methods, like `raiseError`, to raise an error representation when things go wrong. ```scala mdoc:silent -def getTemperatureFromByCoordinatesAlternate[F[_]](x: (Int, Int))(implicit me: MonadError[F, String]): F[Int] = { +def getTemperatureByCoordinatesAlternate[F[_]](x: (Int, Int))(implicit me: MonadError[F, String]): F[Int] = { if (x._1 < 0 || x._2 < 0) me.raiseError("Invalid Coordinates") else for { c <- getCityClosestToCoordinate[F](x) t <- getTemperatureByCity[F](c) } yield t From 4fafcf1e38d92a13c727d170b4e9f9d928da247c Mon Sep 17 00:00:00 2001 From: David Strawn Date: Mon, 10 Jun 2024 14:49:44 -0500 Subject: [PATCH 017/123] Change implicit ordering to match Chain --- .../main/scala/cats/data/NonEmptyVector.scala | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/core/src/main/scala/cats/data/NonEmptyVector.scala b/core/src/main/scala/cats/data/NonEmptyVector.scala index 65225ec534..21f0d403e6 100644 --- a/core/src/main/scala/cats/data/NonEmptyVector.scala +++ b/core/src/main/scala/cats/data/NonEmptyVector.scala @@ -593,26 +593,6 @@ sealed abstract private[data] class NonEmptyVectorInstances extends NonEmptyVect } -sealed abstract private[data] class NonEmptyVectorInstances0 extends NonEmptyVectorInstances1 { - implicit def catsDataHashForNonEmptyVector[A: Hash]: Hash[NonEmptyVector[A]] = - new Hash[NonEmptyVector[A]] { - override def hash(x: NonEmptyVector[A]): Int = - Hash[Vector[A]].hash(x.toVector) - - override def eqv(x: NonEmptyVector[A], y: NonEmptyVector[A]): Boolean = - Hash[Vector[A]].eqv(x.toVector, y.toVector) - } -} - -sealed abstract private[data] class NonEmptyVectorInstances1 extends NonEmptyVectorInstances2 { - implicit def catsDataPartialOrderForNonEmptyVector[A: PartialOrder]: PartialOrder[NonEmptyVector[A]] = - PartialOrder.by[NonEmptyVector[A], Vector[A]](_.toVector) -} - -sealed abstract private[data] class NonEmptyVectorInstances2 { - implicit def catsDataEqForNonEmptyVector[A: Eq]: Eq[NonEmptyVector[A]] = _ === _ -} - object NonEmptyVector extends NonEmptyVectorInstances with Serializable { def apply[A](head: A, tail: Vector[A]): NonEmptyVector[A] = @@ -661,3 +641,17 @@ object NonEmptyVector extends NonEmptyVectorInstances with Serializable { implicit def catsDataEqForZipNonEmptyVector[A: Eq]: Eq[ZipNonEmptyVector[A]] = Eq.by(_.value) } } + +sealed abstract private[data] class NonEmptyVectorInstances0 extends NonEmptyVectorInstances1 { + implicit def catsDataPartialOrderForNonEmptyVector[A: PartialOrder]: PartialOrder[NonEmptyVector[A]] = + PartialOrder.by[NonEmptyVector[A], Vector[A]](_.toVector) +} + +sealed abstract private[data] class NonEmptyVectorInstances1 extends NonEmptyVectorInstances2 { + implicit def catsDataHashForNonEmptyVector[A: Hash]: Hash[NonEmptyVector[A]] = + Hash.by(_.toVector) +} + +sealed abstract private[data] class NonEmptyVectorInstances2 { + implicit def catsDataEqForNonEmptyVector[A: Eq]: Eq[NonEmptyVector[A]] = _ === _ +} From c44252155c3e38ffc8201db5b43c013f2bf41d08 Mon Sep 17 00:00:00 2001 From: satorg Date: Sat, 8 Jun 2024 14:17:46 -0700 Subject: [PATCH 018/123] fix/suppress in 'kernel' --- .../main/scala-2.12/cats/kernel/compat/HashCompat.scala | 6 ++++-- .../main/scala/cats/kernel/instances/MapInstances.scala | 5 ++++- .../main/scala/cats/kernel/instances/SeqInstances.scala | 8 +++++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/kernel/src/main/scala-2.12/cats/kernel/compat/HashCompat.scala b/kernel/src/main/scala-2.12/cats/kernel/compat/HashCompat.scala index 5f21b95f99..411028fd07 100644 --- a/kernel/src/main/scala-2.12/cats/kernel/compat/HashCompat.scala +++ b/kernel/src/main/scala-2.12/cats/kernel/compat/HashCompat.scala @@ -43,9 +43,11 @@ package compat * limitations under the License. */ +import scala.annotation.nowarn + private[kernel] class HashCompat { // Adapted from scala.util.hashing.MurmurHash#productHash. - private[kernel] def product1HashWithPrefix(_1Hash: Int, prefix: String): Int = { + private[kernel] def product1HashWithPrefix(_1Hash: Int, @nowarn("cat=unused") prefix: String): Int = { import scala.util.hashing.MurmurHash3._ var h = productSeed h = mix(h, _1Hash) @@ -53,7 +55,7 @@ private[kernel] class HashCompat { } // Adapted from scala.util.hashing.MurmurHash#productHash. - private[cats] def product2HashWithPrefix(_1Hash: Int, _2Hash: Int, prefix: String): Int = { + private[cats] def product2HashWithPrefix(_1Hash: Int, _2Hash: Int, @nowarn("cat=unused") prefix: String): Int = { import scala.util.hashing.MurmurHash3._ var h = productSeed h = mix(h, _1Hash) diff --git a/kernel/src/main/scala/cats/kernel/instances/MapInstances.scala b/kernel/src/main/scala/cats/kernel/instances/MapInstances.scala index f55ec241b5..528063e7cf 100644 --- a/kernel/src/main/scala/cats/kernel/instances/MapInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/MapInstances.scala @@ -42,12 +42,15 @@ package cats.kernel package instances +import org.typelevel.scalaccompat.annotation.unused + import scala.collection.mutable + import compat.scalaVersionSpecific._ @suppressUnusedImportWarningForScalaVersionSpecific trait MapInstances extends MapInstances1 { - implicit def catsKernelStdHashForMap[K: Hash, V: Hash]: Hash[Map[K, V]] = + implicit def catsKernelStdHashForMap[K, V](implicit @unused K: Hash[K], V: Hash[V]): Hash[Map[K, V]] = new MapHash[K, V] implicit def catsKernelStdCommutativeMonoidForMap[K, V: CommutativeSemigroup]: CommutativeMonoid[Map[K, V]] = diff --git a/kernel/src/main/scala/cats/kernel/instances/SeqInstances.scala b/kernel/src/main/scala/cats/kernel/instances/SeqInstances.scala index 00b737e90f..6282c5e894 100644 --- a/kernel/src/main/scala/cats/kernel/instances/SeqInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/SeqInstances.scala @@ -22,11 +22,11 @@ package cats.kernel package instances -import compat.scalaVersionSpecific._ - import scala.annotation.nowarn import scala.collection.immutable.Seq +import compat.scalaVersionSpecific._ + @suppressUnusedImportWarningForScalaVersionSpecific trait SeqInstances extends SeqInstances1 { implicit def catsKernelStdOrderForSeq[A: Order]: Order[Seq[A]] = @@ -83,7 +83,9 @@ class SeqMonoid[A] extends Monoid[Seq[A]] { } object SeqMonoid { - @nowarn("msg=deprecated") + @nowarn("cat=deprecation") private[this] val singleton: Monoid[Seq[Any]] = new SeqMonoid[Any] + + @nowarn("cat=deprecation") def apply[A]: SeqMonoid[A] = singleton.asInstanceOf[SeqMonoid[A]] } From c2bdebff8b02d02c640aed3d54bf0e7c10e8f0e3 Mon Sep 17 00:00:00 2001 From: satorg Date: Sat, 8 Jun 2024 19:42:23 -0700 Subject: [PATCH 019/123] fix/suppress in 'kernel-laws' --- .../scala/cats/kernel/laws/MonoidLaws.scala | 4 ++- .../scala/cats/kernel/laws/OrderLaws.scala | 2 -- .../kernel/laws/discipline/BoundedTests.scala | 12 +++++++-- .../laws/discipline/EnumerableTests.scala | 25 +++++++++++++------ .../kernel/laws/discipline/HashTests.scala | 5 +++- .../kernel/laws/discipline/MonoidTests.scala | 3 ++- .../kernel/laws/discipline/OrderTests.scala | 5 +++- .../laws/discipline/PartialOrderTests.scala | 5 +++- 8 files changed, 44 insertions(+), 17 deletions(-) diff --git a/kernel-laws/shared/src/main/scala/cats/kernel/laws/MonoidLaws.scala b/kernel-laws/shared/src/main/scala/cats/kernel/laws/MonoidLaws.scala index afe1f54647..93605a8589 100644 --- a/kernel-laws/shared/src/main/scala/cats/kernel/laws/MonoidLaws.scala +++ b/kernel-laws/shared/src/main/scala/cats/kernel/laws/MonoidLaws.scala @@ -35,7 +35,7 @@ trait MonoidLaws[A] extends SemigroupLaws[A] { def repeat0(x: A): IsEq[A] = S.combineN(x, 0) <-> S.empty - def collect0(x: A): IsEq[A] = + def collect0: IsEq[A] = S.combineAll(Nil) <-> S.empty def combineAll(xs: Vector[A]): IsEq[A] = @@ -44,6 +44,8 @@ trait MonoidLaws[A] extends SemigroupLaws[A] { def isId(x: A, eqv: Eq[A]): IsEq[Boolean] = eqv.eqv(x, S.empty) <-> S.isEmpty(x)(eqv) + @deprecated("use `collect0` without parameters", "2.12.1") + def collect0(x: A): IsEq[A] = collect0 } object MonoidLaws { diff --git a/kernel-laws/shared/src/main/scala/cats/kernel/laws/OrderLaws.scala b/kernel-laws/shared/src/main/scala/cats/kernel/laws/OrderLaws.scala index a307fec7d4..f332b7b825 100644 --- a/kernel-laws/shared/src/main/scala/cats/kernel/laws/OrderLaws.scala +++ b/kernel-laws/shared/src/main/scala/cats/kernel/laws/OrderLaws.scala @@ -22,8 +22,6 @@ package cats.kernel package laws -import cats.kernel.Order - trait OrderLaws[A] extends PartialOrderLaws[A] { implicit override def E: Order[A] diff --git a/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/BoundedTests.scala b/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/BoundedTests.scala index 8327b7c2d5..f95b9c0621 100644 --- a/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/BoundedTests.scala +++ b/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/BoundedTests.scala @@ -31,12 +31,16 @@ import org.scalacheck.Prop.forAll trait LowerBoundedTests[A] extends PartialOrderTests[A] { def laws: LowerBoundedLaws[A] - def lowerBounded(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet = + def lowerBounded(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A]): RuleSet = new DefaultRuleSet( "lowerBounded", Some(partialOrder), "bound is less than or equals" -> forAll(laws.boundLteqv _) ) + + @deprecated("use `lowerBounded` without `Eq` parameters", "2.12.1") + def lowerBounded(arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet = + lowerBounded(arbA, arbF) } object LowerBoundedTests { @@ -47,12 +51,16 @@ object LowerBoundedTests { trait UpperBoundedTests[A] extends PartialOrderTests[A] { def laws: UpperBoundedLaws[A] - def upperBounded(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet = + def upperBounded(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A]): RuleSet = new DefaultRuleSet( "upperBounded", Some(partialOrder), "bound is greater than or equals" -> forAll(laws.boundGteqv _) ) + + @deprecated("use `upperBounded` without `Eq` parameters", "2.12.1") + def upperBounded(arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet = + upperBounded(arbA, arbF) } object UpperBoundedTests { diff --git a/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/EnumerableTests.scala b/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/EnumerableTests.scala index d89822ff63..471f89336c 100644 --- a/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/EnumerableTests.scala +++ b/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/EnumerableTests.scala @@ -32,7 +32,7 @@ trait PartialNextTests[A] extends PartialOrderTests[A] { def laws: PartialNextLaws[A] - def partialNext(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet = + def partialNext(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A]): RuleSet = new DefaultRuleSet( "partialNext", Some(partialOrder), @@ -40,13 +40,16 @@ trait PartialNextTests[A] extends PartialOrderTests[A] { "forall a, b. if a < b. next(a) <= b" -> forAll(laws.nextOrderStrong _) ) + @deprecated("use `partialNext` without `Eq` parameters", "2.12.1") + def partialNext(arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet = + partialNext(arbA, arbF) } trait PartialPreviousTests[A] extends PartialOrderTests[A] { def laws: PartialPreviousLaws[A] - def partialPrevious(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet = + def partialPrevious(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A]): RuleSet = new DefaultRuleSet( "partialPrevious", Some(partialOrder), @@ -54,18 +57,16 @@ trait PartialPreviousTests[A] extends PartialOrderTests[A] { "forall a, b. if a < b. next(a) <= b" -> forAll(laws.previousOrderStrong _) ) + @deprecated("use `partialPrevious` without `Eq` parameters", "2.12.1") + def partialPrevious(arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet = + partialPrevious(arbA, arbF) } trait BoundedEnumerableTests[A] extends OrderTests[A] with PartialNextTests[A] with PartialPreviousTests[A] { def laws: BoundedEnumerableLaws[A] - def boundedEnumerable(implicit - arbA: Arbitrary[A], - arbF: Arbitrary[A => A], - eqOA: Eq[Option[A]], - eqA: Eq[A] - ): RuleSet = + def boundedEnumerable(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]]): RuleSet = new RuleSet { val name: String = "boundedEnumerable" val bases: Seq[(String, RuleSet)] = Nil @@ -78,6 +79,14 @@ trait BoundedEnumerableTests[A] extends OrderTests[A] with PartialNextTests[A] w ) } + @deprecated("use `boundedEnumerable` without `Eq[A]` parameter", "2.12.1") + def boundedEnumerable( + arbA: Arbitrary[A], + arbF: Arbitrary[A => A], + eqOA: Eq[Option[A]], + eqA: Eq[A] + ): RuleSet = + boundedEnumerable(arbA, arbF, eqOA) } object BoundedEnumerableTests { diff --git a/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/HashTests.scala b/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/HashTests.scala index b4aeb09893..89b3553267 100644 --- a/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/HashTests.scala +++ b/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/HashTests.scala @@ -34,13 +34,16 @@ trait HashTests[A] extends EqTests[A] { def laws: HashLaws[A] - def hash(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqA: Eq[A], hashA: Hashing[A]): RuleSet = + def hash(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A]): RuleSet = new DefaultRuleSet( "hash", Some(eqv), "hash compatibility" -> forAll(laws.hashCompatibility _) ) + @deprecated("use `hash` without `Hashing` parameter", "2.12.1") + def hash(arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqA: Eq[A], hashA: Hashing[A]): RuleSet = + hash(arbA, arbF) } object HashTests { diff --git a/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/MonoidTests.scala b/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/MonoidTests.scala index 0b90f9b13f..1dbfa247cf 100644 --- a/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/MonoidTests.scala +++ b/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/MonoidTests.scala @@ -26,6 +26,7 @@ package discipline import cats.kernel.instances.boolean._ import org.scalacheck.Arbitrary +import org.scalacheck.Prop import org.scalacheck.Prop.forAll trait MonoidTests[A] extends SemigroupTests[A] { @@ -39,7 +40,7 @@ trait MonoidTests[A] extends SemigroupTests[A] { "left identity" -> forAll(laws.leftIdentity _), "right identity" -> forAll(laws.rightIdentity _), "combine all" -> forAll(laws.combineAll _), - "collect0" -> forAll(laws.collect0 _), + "collect0" -> (laws.collect0: Prop), "is id" -> forAll((a: A) => laws.isId(a, eqA)), "repeat0" -> forAll(laws.repeat0 _) ) diff --git a/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/OrderTests.scala b/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/OrderTests.scala index 14d1493537..017f501dc4 100644 --- a/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/OrderTests.scala +++ b/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/OrderTests.scala @@ -32,7 +32,7 @@ trait OrderTests[A] extends PartialOrderTests[A] { def laws: OrderLaws[A] - def order(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet = + def order(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A]): RuleSet = new DefaultRuleSet( "order", Some(partialOrder), @@ -42,6 +42,9 @@ trait OrderTests[A] extends PartialOrderTests[A] { "min" -> forAll(laws.min _) ) + @deprecated("use `order` without `Eq` parameters", "2.12.1") + def order(arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet = + order(arbA, arbF) } object OrderTests { diff --git a/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/PartialOrderTests.scala b/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/PartialOrderTests.scala index f750f5a284..280522b233 100644 --- a/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/PartialOrderTests.scala +++ b/kernel-laws/shared/src/main/scala/cats/kernel/laws/discipline/PartialOrderTests.scala @@ -32,7 +32,7 @@ trait PartialOrderTests[A] extends EqTests[A] { def laws: PartialOrderLaws[A] - def partialOrder(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet = + def partialOrder(implicit arbA: Arbitrary[A], arbF: Arbitrary[A => A]): RuleSet = new DefaultRuleSet( "partialOrder", Some(eqv), @@ -48,6 +48,9 @@ trait PartialOrderTests[A] extends EqTests[A] { "pmin" -> forAll(laws.pmin _) ) + @deprecated("use `partialOrder` without `Eq` parameters", "2.12.1") + def partialOrder(arbA: Arbitrary[A], arbF: Arbitrary[A => A], eqOA: Eq[Option[A]], eqA: Eq[A]): RuleSet = + partialOrder(arbA, arbF) } object PartialOrderTests { From 4ef2ada895bd2d831a89b2e831cb9ec333f23524 Mon Sep 17 00:00:00 2001 From: Mark Eibes Date: Fri, 14 Jun 2024 11:24:13 +0200 Subject: [PATCH 020/123] Update Newtype.scala --- core/src/main/scala/cats/data/Newtype.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/Newtype.scala b/core/src/main/scala/cats/data/Newtype.scala index dfe162bbdd..4395fc4000 100644 --- a/core/src/main/scala/cats/data/Newtype.scala +++ b/core/src/main/scala/cats/data/Newtype.scala @@ -25,7 +25,7 @@ package data /** * Helper trait for `newtype`s. These allow you to create a zero-allocation wrapper around a specific type. * Similar to `AnyVal` value classes, but never have any runtime overhead. - * It's coped from the newtypes lib by @alexknvl + * It's copied from the newtypes lib by @alexknvl * For more detail see https://github.com/alexknvl/newtypes */ private[data] trait Newtype { self => From 81d052d9d247be6fd12fac60383413d6a6913b4d Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Fri, 14 Jun 2024 16:06:19 +0000 Subject: [PATCH 021/123] Update scalafmt-core to 3.8.2 --- .scalafmt.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index 0bf3b8700e..a530097004 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version=3.8.1 +version=3.8.2 align.openParenCallSite = true align.openParenDefnSite = true maxColumn = 120 From 4c744ff39b943a1bd8422b2f0508f31f8486259d Mon Sep 17 00:00:00 2001 From: Brian Wignall Date: Sat, 15 Jun 2024 15:45:57 -0400 Subject: [PATCH 022/123] Fix broken internal link --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a69e424d2b..3d4ba943d7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -133,7 +133,7 @@ builds: ### Write code -[See guidelines](guidelines.md). +[See guidelines](docs/guidelines.md). ### Attributions From ab606c5785b18f5e9563d754f2a1bf222c634cca Mon Sep 17 00:00:00 2001 From: Brian Wignall Date: Sun, 16 Jun 2024 06:12:41 -0400 Subject: [PATCH 023/123] Update CONTRIBUTING.md Co-authored-by: Daniel Esik --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3d4ba943d7..74c4c4a31a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -133,7 +133,7 @@ builds: ### Write code -[See guidelines](docs/guidelines.md). +[See guidelines](https://typelevel.org/cats/guidelines.html). ### Attributions From 2c93e210f36531975eae4629f012864e39375bfd Mon Sep 17 00:00:00 2001 From: danicheg Date: Sun, 16 Jun 2024 17:13:57 +0400 Subject: [PATCH 024/123] Adjust the JVM options to heal the Native build on CI --- .jvmopts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.jvmopts b/.jvmopts index afbee1f086..330e2416c8 100644 --- a/.jvmopts +++ b/.jvmopts @@ -1,6 +1,9 @@ -Dfile.encoding=UTF8 --Xms1G --Xmx5G --XX:ReservedCodeCacheSize=500M --XX:+TieredCompilation +-Xms2G +-Xmx8G +-Xss4m +-XX:ReservedCodeCacheSize=512m +-XX:MaxMetaspaceSize=512M -XX:+UseParallelGC +-XX:+TieredCompilation +-XX:+UseAdaptiveSizePolicy From 8695da3154b26e312d847ed3a69840307597b77a Mon Sep 17 00:00:00 2001 From: Brian Wignall Date: Sun, 16 Jun 2024 15:29:34 -0400 Subject: [PATCH 025/123] Point to sbt 1.x --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a69e424d2b..835e441994 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,7 +96,7 @@ git clone git@github.com:typelevel/cats.git ``` To build Cats you should have -[sbt](http://www.scala-sbt.org/0.13/tutorial/Setup.html) and [Node.js](https://nodejs.org/) +[sbt](https://www.scala-sbt.org/1.x/docs/Setup.html) and [Node.js](https://nodejs.org/) installed. If you'd like, you can use the [Nix Cats development environment](#nix-cats-development-environment). Run `sbt`, and then use any of the following commands: From 794873ac496c90344ba82ab2d72ca5bf756dfdf9 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:05:12 +0000 Subject: [PATCH 026/123] Update auxlib, clib, javalib, nativelib, ... to 0.5.4 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 5e0abb3d9b..4a415ec7c9 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,5 +4,5 @@ addSbtPlugin("org.typelevel" % "sbt-typelevel-site" % sbtTypelevelVersion) addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") addSbtPlugin("com.github.tkawachi" % "sbt-doctest" % "0.10.0") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") -addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.3") +addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.4") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.12.0") From bcafb0d5727b5a0a77df8ed6d030651ab6262f27 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 00:18:27 +0000 Subject: [PATCH 027/123] Update sbt to 1.10.1 --- project/build.properties | 2 +- scalafix/project/build.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/project/build.properties b/project/build.properties index 081fdbbc76..ee4c672cd0 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.0 +sbt.version=1.10.1 diff --git a/scalafix/project/build.properties b/scalafix/project/build.properties index 081fdbbc76..ee4c672cd0 100644 --- a/scalafix/project/build.properties +++ b/scalafix/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.0 +sbt.version=1.10.1 From 0313f11869171e77c7e7688e487ce75be72c8d95 Mon Sep 17 00:00:00 2001 From: Brian Wignall Date: Mon, 8 Jul 2024 08:55:19 -0400 Subject: [PATCH 028/123] Fix typos --- algebra-core/src/main/scala/algebra/ring/DivisionRing.scala | 2 +- core/src/main/scala/cats/TraverseFilter.scala | 2 +- core/src/main/scala/cats/data/ContT.scala | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/algebra-core/src/main/scala/algebra/ring/DivisionRing.scala b/algebra-core/src/main/scala/algebra/ring/DivisionRing.scala index 75446fcd7a..aa46eaba5a 100644 --- a/algebra-core/src/main/scala/algebra/ring/DivisionRing.scala +++ b/algebra-core/src/main/scala/algebra/ring/DivisionRing.scala @@ -31,7 +31,7 @@ trait DivisionRing[@sp(Byte, Short, Int, Long, Float, Double) A] extends Any wit * This is implemented in terms of basic Ring ops. However, this is * probably significantly less efficient than can be done with a * specific type. So, it is recommended that this method be - * overriden. + * overridden. * * This is possible because a Double is a rational number. */ diff --git a/core/src/main/scala/cats/TraverseFilter.scala b/core/src/main/scala/cats/TraverseFilter.scala index 0907ef3be7..9926efc321 100644 --- a/core/src/main/scala/cats/TraverseFilter.scala +++ b/core/src/main/scala/cats/TraverseFilter.scala @@ -139,7 +139,7 @@ trait TraverseFilter[F[_]] extends FunctorFilter[F] { /** * Removes duplicate elements from a list, keeping only the first occurrence. - * This is usually faster than ordDistinct, especially for things that have a slow comparion (like String). + * This is usually faster than ordDistinct, especially for things that have a slow comparison (like String). */ def hashDistinct[A](fa: F[A])(implicit H: Hash[A]): F[A] = traverseFilter(fa) { a => diff --git a/core/src/main/scala/cats/data/ContT.scala b/core/src/main/scala/cats/data/ContT.scala index 4b2e7b4d77..669aa4cbcf 100644 --- a/core/src/main/scala/cats/data/ContT.scala +++ b/core/src/main/scala/cats/data/ContT.scala @@ -141,7 +141,7 @@ object ContT { * _ <- ContT.callCC( (k: Unit => ContT[IO, Unit, Unit]) => * ContT.liftF(IO.println("this will print first")) >> * k(()) >> - * ContT.liftF(IO.println("this will NOT print as we short-circuit to the contination")) + * ContT.liftF(IO.println("this will NOT print as we short-circuit to the continuation")) * ) * _ <- ContT.liftF(IO.println("this will print second")]) * } yield () From 7ab8e5113ff045fb0f0845621ff29bf015288920 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 20:06:41 +0000 Subject: [PATCH 029/123] Update sbt-typelevel, sbt-typelevel-site to 0.7.2 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 4a415ec7c9..ef6995c3ad 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,4 @@ -val sbtTypelevelVersion = "0.7.1" +val sbtTypelevelVersion = "0.7.2" addSbtPlugin("org.typelevel" % "sbt-typelevel" % sbtTypelevelVersion) addSbtPlugin("org.typelevel" % "sbt-typelevel-site" % sbtTypelevelVersion) addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") From 4c3b161d5d2129744327f978d55e88f093967ec1 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 20:08:17 +0000 Subject: [PATCH 030/123] Run prePR with sbt-typelevel Executed command: sbt tlPrePrBotHook --- .github/workflows/ci.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3798d4f497..32f38c3e55 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,6 +51,10 @@ jobs: runs-on: ${{ matrix.os }} timeout-minutes: 60 steps: + - name: Install sbt + if: contains(runner.os, 'macos') + run: brew install sbt + - name: Checkout current branch (full) uses: actions/checkout@v4 with: @@ -146,6 +150,10 @@ jobs: java: [temurin@8] runs-on: ${{ matrix.os }} steps: + - name: Install sbt + if: contains(runner.os, 'macos') + run: brew install sbt + - name: Checkout current branch (full) uses: actions/checkout@v4 with: @@ -313,6 +321,10 @@ jobs: java: [temurin@8] runs-on: ${{ matrix.os }} steps: + - name: Install sbt + if: contains(runner.os, 'macos') + run: brew install sbt + - name: Checkout current branch (full) uses: actions/checkout@v4 with: @@ -396,6 +408,10 @@ jobs: java: [temurin@8] runs-on: ${{ matrix.os }} steps: + - name: Install sbt + if: contains(runner.os, 'macos') + run: brew install sbt + - name: Checkout current branch (full) uses: actions/checkout@v4 with: @@ -453,6 +469,10 @@ jobs: java: [temurin@17] runs-on: ${{ matrix.os }} steps: + - name: Install sbt + if: contains(runner.os, 'macos') + run: brew install sbt + - name: Checkout current branch (full) uses: actions/checkout@v4 with: From e602fb4e64c15a0984e3d2eab4b7375750afdf47 Mon Sep 17 00:00:00 2001 From: danicheg Date: Sat, 20 Jul 2024 14:45:16 +0400 Subject: [PATCH 031/123] Add EitherOps#leftMapOrKeep --- core/src/main/scala/cats/syntax/either.scala | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/main/scala/cats/syntax/either.scala b/core/src/main/scala/cats/syntax/either.scala index a4361545c0..2b6e7a8944 100644 --- a/core/src/main/scala/cats/syntax/either.scala +++ b/core/src/main/scala/cats/syntax/either.scala @@ -194,6 +194,12 @@ final class EitherOps[A, B](private val eab: Either[A, B]) extends AnyVal { case r @ Right(_) => EitherUtil.leftCast(r) } + def leftMapOrKeep[AA >: A](pf: PartialFunction[A, AA]): Either[AA, B] = + eab match { + case Left(a) => Left(pf.applyOrElse(a, identity[AA])) + case r @ Right(_) => r + } + @deprecated("Included in the standard library", "2.1.0-RC1") private[syntax] def flatMap[AA >: A, D](f: B => Either[AA, D]): Either[AA, D] = eab match { From 03c055e8407a803b4d622b591fd07d28731dccd1 Mon Sep 17 00:00:00 2001 From: danicheg Date: Sat, 20 Jul 2024 15:18:36 +0400 Subject: [PATCH 032/123] Add EitherOps#leftFlatMapOrKeep --- core/src/main/scala/cats/syntax/either.scala | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/main/scala/cats/syntax/either.scala b/core/src/main/scala/cats/syntax/either.scala index 2b6e7a8944..ae29d45c9b 100644 --- a/core/src/main/scala/cats/syntax/either.scala +++ b/core/src/main/scala/cats/syntax/either.scala @@ -213,6 +213,12 @@ final class EitherOps[A, B](private val eab: Either[A, B]) extends AnyVal { case r @ Right(_) => EitherUtil.leftCast(r) } + def leftFlatMapOrKeep[AA >: A, BB >: B](pfa: PartialFunction[A, Either[AA, BB]]): Either[AA, BB] = + eab match { + case l @ Left(a) => pfa.applyOrElse(a, (_: A) => l) + case r @ Right(_) => r + } + def compare[AA >: A, BB >: B](that: Either[AA, BB])(implicit AA: Order[AA], BB: Order[BB]): Int = eab match { case Left(a1) => From 5d74ad532bdeca0c4885718a00aa842d20c64c10 Mon Sep 17 00:00:00 2001 From: danicheg Date: Sat, 20 Jul 2024 15:53:10 +0400 Subject: [PATCH 033/123] Add tests for leftMapOrKeep & leftFlatMapOrKeep --- .../test/scala/cats/tests/EitherSuite.scala | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/shared/src/test/scala/cats/tests/EitherSuite.scala b/tests/shared/src/test/scala/cats/tests/EitherSuite.scala index eca7b226e7..3d0e6cac73 100644 --- a/tests/shared/src/test/scala/cats/tests/EitherSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/EitherSuite.scala @@ -415,6 +415,25 @@ class EitherSuite extends CatsSuite { } } + test("leftFlatMapOrKeep consistent with leftMapOrKeep") { + forAll { (either: Either[String, Int], pf: PartialFunction[String, String]) => + val liftedPF: PartialFunction[String, Either[String, Int]] = { case a => + Either.left[String, Int](pf.applyOrElse(a, identity[String])) + } + assert(either.leftFlatMapOrKeep(liftedPF) === either.leftMapOrKeep(pf)) + } + } + + test("leftFlatMapOrKeep consistent with swap and then flatMapOrKeep") { + import cats.syntax.monad._ + + forAll { (either: Either[String, Int], pf: PartialFunction[String, Either[String, Int]]) => + assert(either.leftFlatMapOrKeep(pf) === either.swap.flatMapOrKeep { case a => + pf.applyOrElse(a, (_: String) => either).swap + }.swap) + } + } + test("raiseWhen raises when true") { val result = Either.raiseWhen(true)("ok") assert(result === Left("ok")) From 1ccfee329c486e7e8b5a685d0f8a311767bd1d97 Mon Sep 17 00:00:00 2001 From: danicheg Date: Sun, 21 Jul 2024 15:17:26 +0400 Subject: [PATCH 034/123] Tweak the case in patmat --- core/src/main/scala/cats/syntax/either.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/scala/cats/syntax/either.scala b/core/src/main/scala/cats/syntax/either.scala index ae29d45c9b..4c1ca96015 100644 --- a/core/src/main/scala/cats/syntax/either.scala +++ b/core/src/main/scala/cats/syntax/either.scala @@ -196,8 +196,8 @@ final class EitherOps[A, B](private val eab: Either[A, B]) extends AnyVal { def leftMapOrKeep[AA >: A](pf: PartialFunction[A, AA]): Either[AA, B] = eab match { - case Left(a) => Left(pf.applyOrElse(a, identity[AA])) - case r @ Right(_) => r + case Left(a) => Left(pf.applyOrElse(a, identity[AA])) + case r: Right[A, B] => r } @deprecated("Included in the standard library", "2.1.0-RC1") @@ -215,8 +215,8 @@ final class EitherOps[A, B](private val eab: Either[A, B]) extends AnyVal { def leftFlatMapOrKeep[AA >: A, BB >: B](pfa: PartialFunction[A, Either[AA, BB]]): Either[AA, BB] = eab match { - case l @ Left(a) => pfa.applyOrElse(a, (_: A) => l) - case r @ Right(_) => r + case l @ Left(a) => pfa.applyOrElse(a, (_: A) => l) + case r: Right[A, B] => r } def compare[AA >: A, BB >: B](that: Either[AA, BB])(implicit AA: Order[AA], BB: Order[BB]): Int = From fb2b43a66b9bd124b80895a8fb15e8fec8ce4f21 Mon Sep 17 00:00:00 2001 From: danicheg Date: Sun, 28 Jul 2024 13:49:28 +0400 Subject: [PATCH 035/123] Replace tut with mdoc on the colophon page --- docs/colophon.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/colophon.md b/docs/colophon.md index 070b7874e2..5b41227fb5 100644 --- a/docs/colophon.md +++ b/docs/colophon.md @@ -12,7 +12,7 @@ integrating them into your own projects. * [scalacheck](http://scalacheck.org) for property-based testing * [discipline](https://github.com/typelevel/discipline) for encoding and testing laws * [kind-projector](https://github.com/typelevel/kind-projector) for type lambda syntax - * [tut](https://github.com/tpolecat/tut) type-checked example code makes sure that our examples stay in sync with the rest of our source + * [mdoc](https://github.com/scalameta/mdoc) type-checked example code makes sure that our examples stay in sync with the rest of our source There are other libraries that aim to foster Functional Programming in the Scala programming language which Cats has a relationship to: From 0c411146c7f5507414e18079b548f1d64f653901 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Mon, 12 Aug 2024 20:04:39 +0000 Subject: [PATCH 036/123] Update munit to 1.0.1 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 3769741007..6735795abe 100644 --- a/build.sbt +++ b/build.sbt @@ -6,7 +6,7 @@ val disciplineVersion = "1.7.0" val disciplineMunitVersion = "2.0.0" -val munitVersion = "1.0.0" +val munitVersion = "1.0.1" val PrimaryJava = JavaSpec.temurin("8") val LTSJava = JavaSpec.temurin("17") From 42a13ba2fc53691f8d8b99c86a5466a29d8868c1 Mon Sep 17 00:00:00 2001 From: danicheg Date: Sun, 18 Aug 2024 15:31:43 +0300 Subject: [PATCH 037/123] Fix the broken link on the typeclasses page --- docs/typeclasses.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/typeclasses.md b/docs/typeclasses.md index 6e7cf551a1..85a4d32f69 100644 --- a/docs/typeclasses.md +++ b/docs/typeclasses.md @@ -233,7 +233,7 @@ From [cats-infographic by @tpolecat](https://github.com/tpolecat/cats-infographi ## Incomplete type class instances in cats -Originally from [@alexknvl](https://gist.github.com/alexknvl/d63508ddb6a728015ace53cb70a1fd5d) +Originally from [@hobwekiva](https://gist.github.com/hobwekiva/d63508ddb6a728015ace53cb70a1fd5d) | Type | Functor | Apply | Applicative | Monad | MonoidK | ApplicativeError | MonadError | CoflatMap | Comonad | Bimonad | From 7c6a05062013511961367dcba58914f15c2a59d8 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Sun, 18 Aug 2024 16:04:59 +0000 Subject: [PATCH 038/123] Update auxlib, clib, javalib, nativelib, ... to 0.5.5 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index ef6995c3ad..a19f2794c1 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,5 +4,5 @@ addSbtPlugin("org.typelevel" % "sbt-typelevel-site" % sbtTypelevelVersion) addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") addSbtPlugin("com.github.tkawachi" % "sbt-doctest" % "0.10.0") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") -addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.4") +addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.5") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.12.0") From 8335cdf369fa8cd416ebfc2ddd40bcb7a8060194 Mon Sep 17 00:00:00 2001 From: danicheg Date: Sat, 24 Aug 2024 13:25:01 +0300 Subject: [PATCH 039/123] Rename root -> cats in build.sbt --- .github/workflows/ci.yml | 116 +++++++++++++++++++-------------------- build.sbt | 2 +- 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 32f38c3e55..1a6e854fef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: os: [ubuntu-latest] scala: [2.12, 2.13, 3] java: [temurin@8, temurin@17, graalvm@17] - project: [rootJS, rootJVM, rootNative] + project: [catsNative, catsJS, catsJVM] exclude: - scala: 2.12 java: temurin@17 @@ -40,13 +40,13 @@ jobs: java: temurin@17 - scala: 3 java: graalvm@17 - - project: rootJS + - project: catsNative java: temurin@17 - - project: rootJS + - project: catsNative java: graalvm@17 - - project: rootNative + - project: catsJS java: temurin@17 - - project: rootNative + - project: catsJS java: graalvm@17 runs-on: ${{ matrix.os }} timeout-minutes: 60 @@ -106,14 +106,14 @@ jobs: if: matrix.java == 'temurin@8' && matrix.os == 'ubuntu-latest' run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' headerCheckAll scalafmtCheckAll 'project /' scalafmtSbtCheck - - name: scalaJSLink - if: matrix.project == 'rootJS' - run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' Test/scalaJSLinkerResult - - name: nativeLink - if: matrix.project == 'rootNative' + if: matrix.project == 'catsNative' run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' Test/nativeLink + - name: scalaJSLink + if: matrix.project == 'catsJS' + run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' Test/scalaJSLinkerResult + - name: Test run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' test @@ -198,92 +198,92 @@ jobs: if: matrix.java == 'graalvm@17' && steps.setup-java-graalvm-17.outputs.cache-hit == 'false' run: sbt +update - - name: Download target directories (2.12, rootJS) + - name: Download target directories (2.12, catsNative) uses: actions/download-artifact@v4 with: - name: target-${{ matrix.os }}-${{ matrix.java }}-2.12-rootJS + name: target-${{ matrix.os }}-${{ matrix.java }}-2.12-catsNative - - name: Inflate target directories (2.12, rootJS) + - name: Inflate target directories (2.12, catsNative) run: | tar xf targets.tar rm targets.tar - - name: Download target directories (2.12, rootJVM) + - name: Download target directories (2.12, catsJS) uses: actions/download-artifact@v4 with: - name: target-${{ matrix.os }}-${{ matrix.java }}-2.12-rootJVM + name: target-${{ matrix.os }}-${{ matrix.java }}-2.12-catsJS - - name: Inflate target directories (2.12, rootJVM) + - name: Inflate target directories (2.12, catsJS) run: | tar xf targets.tar rm targets.tar - - name: Download target directories (2.12, rootNative) + - name: Download target directories (2.12, catsJVM) uses: actions/download-artifact@v4 with: - name: target-${{ matrix.os }}-${{ matrix.java }}-2.12-rootNative + name: target-${{ matrix.os }}-${{ matrix.java }}-2.12-catsJVM - - name: Inflate target directories (2.12, rootNative) + - name: Inflate target directories (2.12, catsJVM) run: | tar xf targets.tar rm targets.tar - - name: Download target directories (2.13, rootJS) + - name: Download target directories (2.13, catsNative) uses: actions/download-artifact@v4 with: - name: target-${{ matrix.os }}-${{ matrix.java }}-2.13-rootJS + name: target-${{ matrix.os }}-${{ matrix.java }}-2.13-catsNative - - name: Inflate target directories (2.13, rootJS) + - name: Inflate target directories (2.13, catsNative) run: | tar xf targets.tar rm targets.tar - - name: Download target directories (2.13, rootJVM) + - name: Download target directories (2.13, catsJS) uses: actions/download-artifact@v4 with: - name: target-${{ matrix.os }}-${{ matrix.java }}-2.13-rootJVM + name: target-${{ matrix.os }}-${{ matrix.java }}-2.13-catsJS - - name: Inflate target directories (2.13, rootJVM) + - name: Inflate target directories (2.13, catsJS) run: | tar xf targets.tar rm targets.tar - - name: Download target directories (2.13, rootNative) + - name: Download target directories (2.13, catsJVM) uses: actions/download-artifact@v4 with: - name: target-${{ matrix.os }}-${{ matrix.java }}-2.13-rootNative + name: target-${{ matrix.os }}-${{ matrix.java }}-2.13-catsJVM - - name: Inflate target directories (2.13, rootNative) + - name: Inflate target directories (2.13, catsJVM) run: | tar xf targets.tar rm targets.tar - - name: Download target directories (3, rootJS) + - name: Download target directories (3, catsNative) uses: actions/download-artifact@v4 with: - name: target-${{ matrix.os }}-${{ matrix.java }}-3-rootJS + name: target-${{ matrix.os }}-${{ matrix.java }}-3-catsNative - - name: Inflate target directories (3, rootJS) + - name: Inflate target directories (3, catsNative) run: | tar xf targets.tar rm targets.tar - - name: Download target directories (3, rootJVM) + - name: Download target directories (3, catsJS) uses: actions/download-artifact@v4 with: - name: target-${{ matrix.os }}-${{ matrix.java }}-3-rootJVM + name: target-${{ matrix.os }}-${{ matrix.java }}-3-catsJS - - name: Inflate target directories (3, rootJVM) + - name: Inflate target directories (3, catsJS) run: | tar xf targets.tar rm targets.tar - - name: Download target directories (3, rootNative) + - name: Download target directories (3, catsJVM) uses: actions/download-artifact@v4 with: - name: target-${{ matrix.os }}-${{ matrix.java }}-3-rootNative + name: target-${{ matrix.os }}-${{ matrix.java }}-3-catsJVM - - name: Inflate target directories (3, rootNative) + - name: Inflate target directories (3, catsJVM) run: | tar xf targets.tar rm targets.tar @@ -372,7 +372,7 @@ jobs: - name: Submit Dependencies uses: scalacenter/sbt-dependency-submission@v2 with: - modules-ignore: rootjs_2.12 rootjs_2.13 rootjs_3 docs_2.12 docs_2.13 docs_3 cats-tests_sjs1_2.12 cats-tests_sjs1_2.13 cats-tests_sjs1_3 rootjvm_2.12 rootjvm_2.13 rootjvm_3 rootnative_2.12 rootnative_2.13 rootnative_3 cats-tests_2.12 cats-tests_2.13 cats-tests_3 bincompattest_2.12 bincompattest_2.13 bincompattest_3 cats-tests_native0.5_2.12 cats-tests_native0.5_2.13 cats-tests_native0.5_3 cats-bench_2.12 cats-bench_2.13 cats-bench_3 + modules-ignore: catsnative_2.12 catsnative_2.13 catsnative_3 docs_2.12 docs_2.13 docs_3 cats-tests_sjs1_2.12 cats-tests_sjs1_2.13 cats-tests_sjs1_3 cats-tests_2.12 cats-tests_2.13 cats-tests_3 catsjs_2.12 catsjs_2.13 catsjs_3 catsjvm_2.12 catsjvm_2.13 catsjvm_3 bincompattest_2.12 bincompattest_2.13 bincompattest_3 cats-tests_native0.5_2.12 cats-tests_native0.5_2.13 cats-tests_native0.5_3 cats-bench_2.12 cats-bench_2.13 cats-bench_3 configs-ignore: test scala-tool scala-doc-tool test-internal validate-steward: @@ -400,12 +400,12 @@ jobs: - run: scala-steward validate-repo-config .scala-steward.conf - scalafix: - name: Scalafix + site: + name: Generate Site strategy: matrix: os: [ubuntu-latest] - java: [temurin@8] + java: [temurin@17] runs-on: ${{ matrix.os }} steps: - name: Install sbt @@ -456,17 +456,23 @@ jobs: if: matrix.java == 'graalvm@17' && steps.setup-java-graalvm-17.outputs.cache-hit == 'false' run: sbt +update - - name: Scalafix tests - run: | - cd scalafix - sbt test + - name: Generate site + run: sbt docs/tlSite - site: - name: Generate Site + - name: Publish site + if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' + uses: peaceiris/actions-gh-pages@v4.0.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: site/target/docs/site + keep_files: true + + scalafix: + name: Scalafix strategy: matrix: os: [ubuntu-latest] - java: [temurin@17] + java: [temurin@8] runs-on: ${{ matrix.os }} steps: - name: Install sbt @@ -517,13 +523,7 @@ jobs: if: matrix.java == 'graalvm@17' && steps.setup-java-graalvm-17.outputs.cache-hit == 'false' run: sbt +update - - name: Generate site - run: sbt docs/tlSite - - - name: Publish site - if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' - uses: peaceiris/actions-gh-pages@v4.0.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: site/target/docs/site - keep_files: true + - name: Scalafix tests + run: | + cd scalafix + sbt test diff --git a/build.sbt b/build.sbt index 6735795abe..e0fe710ca2 100644 --- a/build.sbt +++ b/build.sbt @@ -88,7 +88,7 @@ lazy val testingDependencies = Seq( ) ) -lazy val root = tlCrossRootProject +lazy val cats = tlCrossRootProject .aggregate( kernel, kernelLaws, From 3421eaa6933fd733bec4bb4a9c92b2c7a36c5871 Mon Sep 17 00:00:00 2001 From: Max Smirnov Date: Sat, 31 Aug 2024 20:47:45 +0300 Subject: [PATCH 040/123] Fix foldLeft nomenclature signature --- docs/nomenclature.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/nomenclature.md b/docs/nomenclature.md index eec6e1c114..961b07fb14 100644 --- a/docs/nomenclature.md +++ b/docs/nomenclature.md @@ -111,7 +111,7 @@ Like the previous section, we use the `E` for the error parameter type. | Type | Method Name | Constraints | ------------- |--------------|----------- | `F[A] => A` | `fold` | `A: Monoid` -| `F[A] => B => ((B,A) => B) => F[B]` | `foldLeft` +| `F[A] => B => ((B,A) => B) => B` | `foldLeft` | `F[A] => (A => B) => B` | `foldMap` | `B: Monoid` | `F[A] => (A => G[B]) => G[B]` | `foldMapM` | `G: Monad` and `B: Monoid` | `F[A] => (A => B) => Option[B]` | `collectFirst` | The `A => B` is a `PartialFunction` From 8bfaab5d62b489bf273699924a1ee5efef1eb64d Mon Sep 17 00:00:00 2001 From: Yann Simon Date: Thu, 4 Jul 2024 17:26:09 +0200 Subject: [PATCH 041/123] Issue #4631: Make Later covariant Same as https://github.com/typelevel/cats/pull/937 --- core/src/main/scala/cats/Eval.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/Eval.scala b/core/src/main/scala/cats/Eval.scala index 7834248b3c..ceb6b87fad 100644 --- a/core/src/main/scala/cats/Eval.scala +++ b/core/src/main/scala/cats/Eval.scala @@ -157,7 +157,7 @@ final case class Now[A](value: A) extends Eval.Leaf[A] { * by the closure) will not be retained, and will be available for * garbage collection. */ -final class Later[A](f: () => A) extends Eval.Leaf[A] { +final class Later[+A](f: () => A) extends Eval.Leaf[A] { private[this] var thunk: () => A = f // The idea here is that `f` may have captured very large @@ -206,7 +206,7 @@ object Eval extends EvalInstances { * so calling .value does not trigger * any flatMaps or defers */ - sealed abstract class Leaf[A] extends Eval[A] + sealed abstract class Leaf[+A] extends Eval[A] /** * Construct an eager Eval[A] value (i.e. Now[A]). From 94526a9ae802779ce5e27d7169a6d0d19ad3bad2 Mon Sep 17 00:00:00 2001 From: Yann Simon Date: Fri, 5 Jul 2024 09:20:00 +0200 Subject: [PATCH 042/123] covariant all leafs of eval --- core/src/main/scala/cats/Eval.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/Eval.scala b/core/src/main/scala/cats/Eval.scala index ceb6b87fad..813537e2e0 100644 --- a/core/src/main/scala/cats/Eval.scala +++ b/core/src/main/scala/cats/Eval.scala @@ -139,7 +139,7 @@ sealed abstract class Eval[+A] extends Serializable { self => * This type should be used when an A value is already in hand, or * when the computation to produce an A value is pure and very fast. */ -final case class Now[A](value: A) extends Eval.Leaf[A] { +final case class Now[+A](value: A) extends Eval.Leaf[A] { def memoize: Eval[A] = this } @@ -190,7 +190,7 @@ object Later { * required. It should be avoided except when laziness is required and * caching must be avoided. Generally, prefer Later. */ -final class Always[A](f: () => A) extends Eval.Leaf[A] { +final class Always[+A](f: () => A) extends Eval.Leaf[A] { def value: A = f() def memoize: Eval[A] = new Later(f) } From 3bfaa56e2a3fb2fffe7dd335beb78431fe811897 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2024 12:09:06 +0000 Subject: [PATCH 043/123] Update sbt-typelevel, sbt-typelevel-site to 0.7.3 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index a19f2794c1..5dfb79c96a 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,4 @@ -val sbtTypelevelVersion = "0.7.2" +val sbtTypelevelVersion = "0.7.3" addSbtPlugin("org.typelevel" % "sbt-typelevel" % sbtTypelevelVersion) addSbtPlugin("org.typelevel" % "sbt-typelevel-site" % sbtTypelevelVersion) addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") From 107856ad130996d079d28dd13173375412d46eeb Mon Sep 17 00:00:00 2001 From: danicheg Date: Sun, 8 Sep 2024 13:31:19 +0300 Subject: [PATCH 044/123] Resolve the com.lihaoyi.geny dependency conflict MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michael Pilquist Co-authored-by: Marco Zühlke --- project/plugins.sbt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/project/plugins.sbt b/project/plugins.sbt index 5dfb79c96a..90eccd41ea 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -6,3 +6,5 @@ addSbtPlugin("com.github.tkawachi" % "sbt-doctest" % "0.10.0") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.5") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.12.0") + +libraryDependencySchemes += "com.lihaoyi" %% "geny" % VersionScheme.Always From 6fca8def4fcfc341e3522aba0667da11adf3d1b8 Mon Sep 17 00:00:00 2001 From: danicheg Date: Sun, 8 Sep 2024 13:37:03 +0300 Subject: [PATCH 045/123] Regenerate ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a6e854fef..5443795f7f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -314,7 +314,7 @@ jobs: dependency-submission: name: Submit Dependencies - if: github.event_name != 'pull_request' + if: github.event.repository.fork == false && github.event_name != 'pull_request' strategy: matrix: os: [ubuntu-latest] From d589a9f70c66b9c685460b0bbc63b455096c2636 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 12:07:04 +0000 Subject: [PATCH 046/123] Update munit to 1.0.2 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index e0fe710ca2..6c96b7d774 100644 --- a/build.sbt +++ b/build.sbt @@ -6,7 +6,7 @@ val disciplineVersion = "1.7.0" val disciplineMunitVersion = "2.0.0" -val munitVersion = "1.0.1" +val munitVersion = "1.0.2" val PrimaryJava = JavaSpec.temurin("8") val LTSJava = JavaSpec.temurin("17") From 6a15009e42909507dde55b13bb1378b83ee85fbe Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 00:20:28 +0000 Subject: [PATCH 047/123] Update sbt to 1.10.2 --- project/build.properties | 2 +- scalafix/project/build.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/project/build.properties b/project/build.properties index ee4c672cd0..0b699c3052 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.1 +sbt.version=1.10.2 diff --git a/scalafix/project/build.properties b/scalafix/project/build.properties index ee4c672cd0..0b699c3052 100644 --- a/scalafix/project/build.properties +++ b/scalafix/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.1 +sbt.version=1.10.2 From 9e87de045c4a92725dc4baf6241305f063407035 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:06:59 +0000 Subject: [PATCH 048/123] Update scala-library, scala-reflect to 2.12.20 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 6c96b7d774..bf24998a07 100644 --- a/build.sbt +++ b/build.sbt @@ -14,7 +14,7 @@ val GraalVM = JavaSpec.graalvm("17") ThisBuild / githubWorkflowJavaVersions := Seq(PrimaryJava, LTSJava, GraalVM) -val Scala212 = "2.12.19" +val Scala212 = "2.12.20" val Scala213 = "2.13.14" val Scala3 = "3.3.3" From 3c5fecc58f45150d80c70f7acef63a7badcb9c96 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Sun, 15 Sep 2024 20:06:09 +0000 Subject: [PATCH 049/123] Update scalacheck to 1.18.1 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index bf24998a07..90fc5eeffd 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ ThisBuild / tlBaseVersion := "2.12" -val scalaCheckVersion = "1.18.0" +val scalaCheckVersion = "1.18.1" val disciplineVersion = "1.7.0" From 025867d0e3340b0b0fcfd1d091710f4a574b6397 Mon Sep 17 00:00:00 2001 From: Patrick Oscar Boykin Date: Sun, 22 Sep 2024 11:44:30 -1000 Subject: [PATCH 050/123] Add Defer.recursiveFn to aid in recursion --- core/src/main/scala/cats/Defer.scala | 23 +++++++++++++++++++ .../src/test/scala/cats/tests/EvalSuite.scala | 13 +++++++++++ 2 files changed, 36 insertions(+) diff --git a/core/src/main/scala/cats/Defer.scala b/core/src/main/scala/cats/Defer.scala index 01adbee1d7..518e54f5dc 100644 --- a/core/src/main/scala/cats/Defer.scala +++ b/core/src/main/scala/cats/Defer.scala @@ -72,6 +72,29 @@ trait Defer[F[_]] extends Serializable { lazy val res: F[A] = fn(defer(res)) res } + + /** + * Useful when you want a recursive function that returns F where + * F[_]: Defer. Examples include IO, Eval, or transformers such + * as EitherT or OptionT. + * + * example: + * + * val sumTo: Int => Eval[Int] = + * Defer[Eval].recursiveFn[Int, Int] { recur => + * + * { i => + * if (i > 0) recur(i - 1).map(_ + i) + * else Eval.now(0) + * } + * } + */ + def recursiveFn[A, B](fn: (A => F[B]) => (A => F[B])): A => F[B] = + new Function1[A, F[B]] { self => + lazy val loopFn: A => F[B] = fn(self) + + def apply(a: A): F[B] = defer(loopFn(a)) + } } object Defer { diff --git a/tests/shared/src/test/scala/cats/tests/EvalSuite.scala b/tests/shared/src/test/scala/cats/tests/EvalSuite.scala index f64a780051..3819f36e2e 100644 --- a/tests/shared/src/test/scala/cats/tests/EvalSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/EvalSuite.scala @@ -297,4 +297,17 @@ class EvalSuite extends CatsSuite { assert(n2 == 1) } } + + test("test Defer.recursiveFn example") { + val sumTo: Int => Eval[Int] = + cats.Defer[Eval].recursiveFn[Int, Int] { recur => + + { i => + if (i > 0) recur(i - 1).map(_ + i) + else Eval.now(0) + } + } + + assert(sumTo(300000).value == (0 to 300000).sum) + } } From e45b590bf1775da896dc58f27528f706eb5be447 Mon Sep 17 00:00:00 2001 From: Patrick Oscar Boykin Date: Sun, 22 Sep 2024 11:51:17 -1000 Subject: [PATCH 051/123] actually, there is no reason to make loopFn lazy --- core/src/main/scala/cats/Defer.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/Defer.scala b/core/src/main/scala/cats/Defer.scala index 518e54f5dc..a4fd3da24d 100644 --- a/core/src/main/scala/cats/Defer.scala +++ b/core/src/main/scala/cats/Defer.scala @@ -91,7 +91,7 @@ trait Defer[F[_]] extends Serializable { */ def recursiveFn[A, B](fn: (A => F[B]) => (A => F[B])): A => F[B] = new Function1[A, F[B]] { self => - lazy val loopFn: A => F[B] = fn(self) + val loopFn: A => F[B] = fn(self) def apply(a: A): F[B] = defer(loopFn(a)) } From d6c052172fc80c9674ad19c7c448e518c538f8fc Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 20:08:40 +0000 Subject: [PATCH 052/123] Update scala-library, scala-reflect to 2.13.15 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 90fc5eeffd..a99b372136 100644 --- a/build.sbt +++ b/build.sbt @@ -15,7 +15,7 @@ val GraalVM = JavaSpec.graalvm("17") ThisBuild / githubWorkflowJavaVersions := Seq(PrimaryJava, LTSJava, GraalVM) val Scala212 = "2.12.20" -val Scala213 = "2.13.14" +val Scala213 = "2.13.15" val Scala3 = "3.3.3" ThisBuild / crossScalaVersions := Seq(Scala212, Scala213, Scala3) From 518b0322172bea68ba14e93804b3fbbaa52bf360 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:09:00 +0000 Subject: [PATCH 053/123] Update scala3-library, ... to 3.3.4 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index a99b372136..44fc00755c 100644 --- a/build.sbt +++ b/build.sbt @@ -16,7 +16,7 @@ ThisBuild / githubWorkflowJavaVersions := Seq(PrimaryJava, LTSJava, GraalVM) val Scala212 = "2.12.20" val Scala213 = "2.13.15" -val Scala3 = "3.3.3" +val Scala3 = "3.3.4" ThisBuild / crossScalaVersions := Seq(Scala212, Scala213, Scala3) ThisBuild / scalaVersion := Scala213 From 1e78fe8139f889440a02b5b370ef230cb371fd8b Mon Sep 17 00:00:00 2001 From: satorg Date: Sat, 28 Sep 2024 11:41:58 -0700 Subject: [PATCH 054/123] fix some awkward imports --- core/src/main/scala/cats/Bifunctor.scala | 2 +- core/src/main/scala/cats/Functor.scala | 6 +++--- .../src/test/scala/cats/tests/IndexedStateTSuite.scala | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/cats/Bifunctor.scala b/core/src/main/scala/cats/Bifunctor.scala index cf328caa5d..58915b08bf 100644 --- a/core/src/main/scala/cats/Bifunctor.scala +++ b/core/src/main/scala/cats/Bifunctor.scala @@ -80,7 +80,7 @@ trait Bifunctor[F[_, _]] extends Serializable { self => * Lift left into F using Applicative. * * Example: * {{{ - * scala> import cats.implicits._ + * scala> import cats.syntax.all._ * scala> val x0: Either[String, Int] = Either.left("foo") * scala> val x1: Either[List[String], Int] = x0.leftLiftTo[List] * }}} diff --git a/core/src/main/scala/cats/Functor.scala b/core/src/main/scala/cats/Functor.scala index 6f42a7a750..dbfd70cd0b 100644 --- a/core/src/main/scala/cats/Functor.scala +++ b/core/src/main/scala/cats/Functor.scala @@ -79,7 +79,7 @@ trait Functor[F[_]] extends Invariant[F] { self => * Example: * {{{ * scala> import cats.Functor - * scala> import cats.implicits.catsStdInstancesForOption + * scala> import cats.syntax.all._ * * scala> val o = Option(42) * scala> Functor[Option].lift((x: Int) => x + 10)(o) @@ -189,7 +189,7 @@ trait Functor[F[_]] extends Invariant[F] { self => * * {{{ * scala> import cats.Functor - * scala> import cats.implicits.catsStdInstancesForList + * scala> import cats.syntax.all._ * * scala> Functor[List].unzip(List((1,2), (3, 4))) * res0: (List[Int], List[Int]) = (List(1, 3),List(2, 4)) @@ -203,7 +203,7 @@ trait Functor[F[_]] extends Invariant[F] { self => * Example: * {{{ * scala> import cats.Functor - * scala> import cats.implicits.catsStdInstancesForList + * scala> import cats.syntax.all._ * * scala> Functor[List].ifF(List(true, false, false))(1, 0) * res0: List[Int] = List(1, 0, 0) diff --git a/tests/shared/src/test/scala/cats/tests/IndexedStateTSuite.scala b/tests/shared/src/test/scala/cats/tests/IndexedStateTSuite.scala index 3983e406cf..839b38eabf 100644 --- a/tests/shared/src/test/scala/cats/tests/IndexedStateTSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/IndexedStateTSuite.scala @@ -350,7 +350,6 @@ class IndexedStateTSuite extends CatsSuite { test("fromState correctly turns State[A, F[B]] into StateT[F, A, B]") { val state: State[Int, Option[Int]] = add1.map(Some.apply) - import cats.implicits.catsStdInstancesForOption forAll { (initial: Int) => assert(StateT.fromState(state).run(initial).get === { val (s, Some(result)) = state.run(initial).value: @unchecked // non-exhaustive match warning From 8d53b5806f10d85d7cd6aea1113787e4e7887c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Sun, 29 Sep 2024 20:03:22 +0200 Subject: [PATCH 055/123] Add AnyVal --- project/Boilerplate.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index 2f95f75a16..277a967cd6 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -647,12 +647,12 @@ object Boilerplate { - implicit def catsSyntaxFunction${arity}Apply[T, ${`A..N`}](f: $function): Function${arity}ApplyOps[T, ${`A..N`}] = new Function${arity}ApplyOps(f) |} | - |private[syntax] final class Function1ApplyOps[T, A0](private val f: Function1[A0, T]) extends Serializable { + |private[syntax] final class Function1ApplyOps[T, A0](private val f: Function1[A0, T]) extends AnyVal with Serializable { | def liftN[F[_]: Functor](a0: F[A0]): F[T] = Functor[F].map(a0)(f) | def parLiftN[F[_]: Functor](a0: F[A0]): F[T] = Functor[F].map(a0)(f) |} | - -private[syntax] final class Function${arity}ApplyOps[T, ${`A..N`}](private val f: $function) extends Serializable { + -private[syntax] final class Function${arity}ApplyOps[T, ${`A..N`}](private val f: $function) extends AnyVal with Serializable { - def liftN[F[_]: Functor: Semigroupal]($typedParams): F[T] = Semigroupal.map$arity(${`a..n`})(f) - def parLiftN[F[_]: Parallel]($typedParams): F[T] = Parallel.parMap$arity(${`a..n`})(f) -} From 6e60daa4d095593153a13726bb4577bc8ccd2751 Mon Sep 17 00:00:00 2001 From: Andrew Valencik Date: Sat, 5 Oct 2024 09:41:52 -0400 Subject: [PATCH 056/123] Update sponsors.js to new API values --- docs/js/sponsors.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/js/sponsors.js b/docs/js/sponsors.js index c64d9e270c..fd22d9ad62 100644 --- a/docs/js/sponsors.js +++ b/docs/js/sponsors.js @@ -38,11 +38,11 @@ var sponsors = async function () { for (i = 0; i < members.length; i++) { var member = members[i]; switch (member.tier ? member.tier.name : null) { - case 'platinum-sponsor': + case 'Platinum Sponsor': addSponsor('platinum-sponsors', member.account, PlatinumSize); - case 'gold-sponsor': + case 'Gold Sponsor': addSponsor('gold-sponsors', member.account, GoldSize); - case 'silver-sponsor': + case 'Silver Sponsor': addSponsor('silver-sponsors', member.account, SilverSize); case 'backer': addSponsor('backers', member.account, BackerSize); From 6512b68eb0b845e939937f4f91bf8b6c2e7e5aec Mon Sep 17 00:00:00 2001 From: Mickey Donaghy Date: Tue, 8 Oct 2024 10:54:13 +0900 Subject: [PATCH 057/123] Add `unorderedFoldMapA` method --- .../main/scala/cats/UnorderedFoldable.scala | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/UnorderedFoldable.scala b/core/src/main/scala/cats/UnorderedFoldable.scala index 6a41b2a8aa..0078ffe2c8 100644 --- a/core/src/main/scala/cats/UnorderedFoldable.scala +++ b/core/src/main/scala/cats/UnorderedFoldable.scala @@ -35,6 +35,27 @@ trait UnorderedFoldable[F[_]] extends Serializable { def unorderedFold[A: CommutativeMonoid](fa: F[A]): A = unorderedFoldMap(fa)(identity) + /** + * Fold in a [[CommutativeApplicative]] context by mapping the `A` values to `G[B]`. combining + * the `B` values using the given `CommutativeMonoid[B]` instance. + * + * {{{ + * scala> import cats.UnorderedFoldable + * scala> import cats.syntax.all._ + * scala> val evenNumbers = Set(2,4,6,8,10) + * scala> val evenOpt: Int => Option[Int] = + * | i => if (i % 2 == 0) Some(i) else None + * scala> UnorderedFoldable[Set].unorderedFoldMapA(evenNumbers)(evenOpt) + * res0: Option[Int] = Some(30) + * scala> UnorderedFoldable[Set].foldMapA(evenNumbers :+ 11)(evenOpt) + * res1: Option[Int] = None + * }}} + */ + def unorderedFoldMapA[G[_], A, B](fa: F[A])( + f: A => G[B] + )(implicit G: CommutativeApplicative[G], B: CommutativeMonoid[B]): G[B] = + unorderedFoldMap(fa)(f)(CommutativeApplicative.commutativeMonoidFor) + /** * Tests if `fa` contains `v` using the `Eq` instance for `A` */ @@ -170,6 +191,10 @@ object UnorderedFoldable def unorderedFoldMap[B](f: A => B)(implicit ev$1: CommutativeMonoid[B]): B = typeClassInstance.unorderedFoldMap[A, B](self)(f) def unorderedFold(implicit ev$1: CommutativeMonoid[A]): A = typeClassInstance.unorderedFold[A](self) + def unorderedFoldMapA[G[_], B]( + f: A => G[B] + )(implicit ev$1: CommutativeApplicative[G], ev$2: CommutativeMonoid[B]): G[B] = + typeClassInstance.unorderedFoldMapA[G, A, B](self)(f) def isEmpty: Boolean = typeClassInstance.isEmpty[A](self) def nonEmpty: Boolean = typeClassInstance.nonEmpty[A](self) def exists(p: A => Boolean): Boolean = typeClassInstance.exists[A](self)(p) @@ -189,5 +214,4 @@ object UnorderedFoldable } @deprecated("Use cats.syntax object imports", "2.2.0") object nonInheritedOps extends ToUnorderedFoldableOps - } From a8ff6c7a1698e955c773b5c931c6d71975f6208f Mon Sep 17 00:00:00 2001 From: Mickey Donaghy Date: Tue, 8 Oct 2024 11:04:43 +0900 Subject: [PATCH 058/123] Call the correct method in the doctest --- core/src/main/scala/cats/UnorderedFoldable.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/UnorderedFoldable.scala b/core/src/main/scala/cats/UnorderedFoldable.scala index 0078ffe2c8..099d955ca3 100644 --- a/core/src/main/scala/cats/UnorderedFoldable.scala +++ b/core/src/main/scala/cats/UnorderedFoldable.scala @@ -47,7 +47,7 @@ trait UnorderedFoldable[F[_]] extends Serializable { * | i => if (i % 2 == 0) Some(i) else None * scala> UnorderedFoldable[Set].unorderedFoldMapA(evenNumbers)(evenOpt) * res0: Option[Int] = Some(30) - * scala> UnorderedFoldable[Set].foldMapA(evenNumbers :+ 11)(evenOpt) + * scala> UnorderedFoldable[Set].unorderedFoldMapA(evenNumbers :+ 11)(evenOpt) * res1: Option[Int] = None * }}} */ From 77d2a0f968609a686eec737d3eaaffa7111c852b Mon Sep 17 00:00:00 2001 From: Mickey Donaghy Date: Tue, 8 Oct 2024 11:10:40 +0900 Subject: [PATCH 059/123] Call a set method not a list one, that's the whole point --- core/src/main/scala/cats/UnorderedFoldable.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/UnorderedFoldable.scala b/core/src/main/scala/cats/UnorderedFoldable.scala index 099d955ca3..da17638d3a 100644 --- a/core/src/main/scala/cats/UnorderedFoldable.scala +++ b/core/src/main/scala/cats/UnorderedFoldable.scala @@ -47,7 +47,7 @@ trait UnorderedFoldable[F[_]] extends Serializable { * | i => if (i % 2 == 0) Some(i) else None * scala> UnorderedFoldable[Set].unorderedFoldMapA(evenNumbers)(evenOpt) * res0: Option[Int] = Some(30) - * scala> UnorderedFoldable[Set].unorderedFoldMapA(evenNumbers :+ 11)(evenOpt) + * scala> UnorderedFoldable[Set].unorderedFoldMapA(evenNumbers + 11)(evenOpt) * res1: Option[Int] = None * }}} */ From 035b7be498cc99108abf25783a8efa5d5dd8bc6a Mon Sep 17 00:00:00 2001 From: Mickey Donaghy Date: Wed, 9 Oct 2024 15:33:20 +0900 Subject: [PATCH 060/123] Add identity law for unorderedFoldMapA --- laws/src/main/scala/cats/laws/UnorderedFoldableLaws.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/laws/src/main/scala/cats/laws/UnorderedFoldableLaws.scala b/laws/src/main/scala/cats/laws/UnorderedFoldableLaws.scala index 31ce99b079..e70df54e0c 100644 --- a/laws/src/main/scala/cats/laws/UnorderedFoldableLaws.scala +++ b/laws/src/main/scala/cats/laws/UnorderedFoldableLaws.scala @@ -30,6 +30,9 @@ trait UnorderedFoldableLaws[F[_]] { def unorderedFoldConsistentWithUnorderedFoldMap[A: CommutativeMonoid](fa: F[A]): IsEq[A] = F.unorderedFoldMap(fa)(identity) <-> F.unorderedFold(fa) + def unorderedFoldMapAIdentity[A, B: CommutativeMonoid](fa: F[A], f: A => B): IsEq[B] = + F.unorderedFoldMapA[Id, A, B](fa)(f) <-> F.unorderedFoldMap(fa)(f) + def forallConsistentWithExists[A](fa: F[A], p: A => Boolean): Boolean = if (F.forall(fa)(p)) { val negationExists = F.exists(fa)(a => !p(a)) From 2fd1efd20ef80b7f0eafd0679afbc978ee84526f Mon Sep 17 00:00:00 2001 From: Mickey Donaghy Date: Thu, 10 Oct 2024 08:45:36 +0900 Subject: [PATCH 061/123] Actually test the identity law I added --- .../main/scala/cats/laws/discipline/UnorderedFoldableTests.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/laws/src/main/scala/cats/laws/discipline/UnorderedFoldableTests.scala b/laws/src/main/scala/cats/laws/discipline/UnorderedFoldableTests.scala index 4959985576..29a4e737c9 100644 --- a/laws/src/main/scala/cats/laws/discipline/UnorderedFoldableTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/UnorderedFoldableTests.scala @@ -45,6 +45,7 @@ trait UnorderedFoldableTests[F[_]] extends Laws { name = "unorderedFoldable", parent = None, "unorderedFold consistent with unorderedFoldMap" -> forAll(laws.unorderedFoldConsistentWithUnorderedFoldMap[A] _), + "unorderedFoldMapA identity" -> forAll(laws.unorderedFoldMapAIdentity[A, B] _), "forall consistent with exists" -> forAll(laws.forallConsistentWithExists[A] _), "forall true if empty" -> forAll(laws.forallEmpty[A] _), "nonEmpty reference" -> forAll(laws.nonEmptyRef[A] _), From 2114709f913c56f842192576135201a586bcc01f Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Fri, 11 Oct 2024 04:08:03 +0000 Subject: [PATCH 062/123] Update sbt-typelevel, sbt-typelevel-site to 0.7.4 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 90eccd41ea..76f8e1e6d7 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,4 @@ -val sbtTypelevelVersion = "0.7.3" +val sbtTypelevelVersion = "0.7.4" addSbtPlugin("org.typelevel" % "sbt-typelevel" % sbtTypelevelVersion) addSbtPlugin("org.typelevel" % "sbt-typelevel-site" % sbtTypelevelVersion) addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") From 92dd62e3ac3c5704900a4ac4c0d71f129c4a6c34 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Fri, 11 Oct 2024 04:09:38 +0000 Subject: [PATCH 063/123] Run prePR with sbt-typelevel Executed command: sbt tlPrePrBotHook --- .github/workflows/ci.yml | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5443795f7f..4919b23327 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,8 +52,7 @@ jobs: timeout-minutes: 60 steps: - name: Install sbt - if: contains(runner.os, 'macos') - run: brew install sbt + uses: sbt/setup-sbt@v1 - name: Checkout current branch (full) uses: actions/checkout@v4 @@ -89,7 +88,7 @@ jobs: - name: Setup Java (graalvm@17) id: setup-java-graalvm-17 if: matrix.java == 'graalvm@17' - uses: graalvm/setup-graalvm@v1 + uses: actions/setup-java@v4 with: distribution: graalvm java-version: 17 @@ -151,8 +150,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Install sbt - if: contains(runner.os, 'macos') - run: brew install sbt + uses: sbt/setup-sbt@v1 - name: Checkout current branch (full) uses: actions/checkout@v4 @@ -188,7 +186,7 @@ jobs: - name: Setup Java (graalvm@17) id: setup-java-graalvm-17 if: matrix.java == 'graalvm@17' - uses: graalvm/setup-graalvm@v1 + uses: actions/setup-java@v4 with: distribution: graalvm java-version: 17 @@ -322,8 +320,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Install sbt - if: contains(runner.os, 'macos') - run: brew install sbt + uses: sbt/setup-sbt@v1 - name: Checkout current branch (full) uses: actions/checkout@v4 @@ -359,7 +356,7 @@ jobs: - name: Setup Java (graalvm@17) id: setup-java-graalvm-17 if: matrix.java == 'graalvm@17' - uses: graalvm/setup-graalvm@v1 + uses: actions/setup-java@v4 with: distribution: graalvm java-version: 17 @@ -409,8 +406,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Install sbt - if: contains(runner.os, 'macos') - run: brew install sbt + uses: sbt/setup-sbt@v1 - name: Checkout current branch (full) uses: actions/checkout@v4 @@ -446,7 +442,7 @@ jobs: - name: Setup Java (graalvm@17) id: setup-java-graalvm-17 if: matrix.java == 'graalvm@17' - uses: graalvm/setup-graalvm@v1 + uses: actions/setup-java@v4 with: distribution: graalvm java-version: 17 @@ -476,8 +472,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Install sbt - if: contains(runner.os, 'macos') - run: brew install sbt + uses: sbt/setup-sbt@v1 - name: Checkout current branch (full) uses: actions/checkout@v4 @@ -513,7 +508,7 @@ jobs: - name: Setup Java (graalvm@17) id: setup-java-graalvm-17 if: matrix.java == 'graalvm@17' - uses: graalvm/setup-graalvm@v1 + uses: actions/setup-java@v4 with: distribution: graalvm java-version: 17 From 505d73db8d1e2dbc6775fd6196a53c26b0af9eb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Zu=CC=88hlke?= Date: Mon, 21 Oct 2024 17:36:34 +0200 Subject: [PATCH 064/123] Update GraalVM from 17 to 21 GraalVM is no longer available under the free license: graalvm/setup-graalvm#notes-on-oracle-graalvm-for-jdk-17 sbt-typelevel already did the same: typelevel/sbt-typelevel#763 --- .github/workflows/ci.yml | 60 ++++++++++++++++++++-------------------- build.sbt | 2 +- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4919b23327..8740ddae2d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,25 +29,25 @@ jobs: matrix: os: [ubuntu-latest] scala: [2.12, 2.13, 3] - java: [temurin@8, temurin@17, graalvm@17] + java: [temurin@8, temurin@17, graalvm@21] project: [catsNative, catsJS, catsJVM] exclude: - scala: 2.12 java: temurin@17 - scala: 2.12 - java: graalvm@17 + java: graalvm@21 - scala: 3 java: temurin@17 - scala: 3 - java: graalvm@17 + java: graalvm@21 - project: catsNative java: temurin@17 - project: catsNative - java: graalvm@17 + java: graalvm@21 - project: catsJS java: temurin@17 - project: catsJS - java: graalvm@17 + java: graalvm@21 runs-on: ${{ matrix.os }} timeout-minutes: 60 steps: @@ -85,17 +85,17 @@ jobs: if: matrix.java == 'temurin@17' && steps.setup-java-temurin-17.outputs.cache-hit == 'false' run: sbt +update - - name: Setup Java (graalvm@17) - id: setup-java-graalvm-17 - if: matrix.java == 'graalvm@17' + - name: Setup Java (graalvm@21) + id: setup-java-graalvm-21 + if: matrix.java == 'graalvm@21' uses: actions/setup-java@v4 with: distribution: graalvm - java-version: 17 + java-version: 21 cache: sbt - name: sbt update - if: matrix.java == 'graalvm@17' && steps.setup-java-graalvm-17.outputs.cache-hit == 'false' + if: matrix.java == 'graalvm@21' && steps.setup-java-graalvm-21.outputs.cache-hit == 'false' run: sbt +update - name: Check that workflows are up to date @@ -183,17 +183,17 @@ jobs: if: matrix.java == 'temurin@17' && steps.setup-java-temurin-17.outputs.cache-hit == 'false' run: sbt +update - - name: Setup Java (graalvm@17) - id: setup-java-graalvm-17 - if: matrix.java == 'graalvm@17' + - name: Setup Java (graalvm@21) + id: setup-java-graalvm-21 + if: matrix.java == 'graalvm@21' uses: actions/setup-java@v4 with: distribution: graalvm - java-version: 17 + java-version: 21 cache: sbt - name: sbt update - if: matrix.java == 'graalvm@17' && steps.setup-java-graalvm-17.outputs.cache-hit == 'false' + if: matrix.java == 'graalvm@21' && steps.setup-java-graalvm-21.outputs.cache-hit == 'false' run: sbt +update - name: Download target directories (2.12, catsNative) @@ -353,17 +353,17 @@ jobs: if: matrix.java == 'temurin@17' && steps.setup-java-temurin-17.outputs.cache-hit == 'false' run: sbt +update - - name: Setup Java (graalvm@17) - id: setup-java-graalvm-17 - if: matrix.java == 'graalvm@17' + - name: Setup Java (graalvm@21) + id: setup-java-graalvm-21 + if: matrix.java == 'graalvm@21' uses: actions/setup-java@v4 with: distribution: graalvm - java-version: 17 + java-version: 21 cache: sbt - name: sbt update - if: matrix.java == 'graalvm@17' && steps.setup-java-graalvm-17.outputs.cache-hit == 'false' + if: matrix.java == 'graalvm@21' && steps.setup-java-graalvm-21.outputs.cache-hit == 'false' run: sbt +update - name: Submit Dependencies @@ -439,17 +439,17 @@ jobs: if: matrix.java == 'temurin@17' && steps.setup-java-temurin-17.outputs.cache-hit == 'false' run: sbt +update - - name: Setup Java (graalvm@17) - id: setup-java-graalvm-17 - if: matrix.java == 'graalvm@17' + - name: Setup Java (graalvm@21) + id: setup-java-graalvm-21 + if: matrix.java == 'graalvm@21' uses: actions/setup-java@v4 with: distribution: graalvm - java-version: 17 + java-version: 21 cache: sbt - name: sbt update - if: matrix.java == 'graalvm@17' && steps.setup-java-graalvm-17.outputs.cache-hit == 'false' + if: matrix.java == 'graalvm@21' && steps.setup-java-graalvm-21.outputs.cache-hit == 'false' run: sbt +update - name: Generate site @@ -505,17 +505,17 @@ jobs: if: matrix.java == 'temurin@17' && steps.setup-java-temurin-17.outputs.cache-hit == 'false' run: sbt +update - - name: Setup Java (graalvm@17) - id: setup-java-graalvm-17 - if: matrix.java == 'graalvm@17' + - name: Setup Java (graalvm@21) + id: setup-java-graalvm-21 + if: matrix.java == 'graalvm@21' uses: actions/setup-java@v4 with: distribution: graalvm - java-version: 17 + java-version: 21 cache: sbt - name: sbt update - if: matrix.java == 'graalvm@17' && steps.setup-java-graalvm-17.outputs.cache-hit == 'false' + if: matrix.java == 'graalvm@21' && steps.setup-java-graalvm-21.outputs.cache-hit == 'false' run: sbt +update - name: Scalafix tests diff --git a/build.sbt b/build.sbt index 44fc00755c..8dfba21b7e 100644 --- a/build.sbt +++ b/build.sbt @@ -10,7 +10,7 @@ val munitVersion = "1.0.2" val PrimaryJava = JavaSpec.temurin("8") val LTSJava = JavaSpec.temurin("17") -val GraalVM = JavaSpec.graalvm("17") +val GraalVM = JavaSpec.graalvm("21") ThisBuild / githubWorkflowJavaVersions := Seq(PrimaryJava, LTSJava, GraalVM) From 2897676a7e9e7be1ed07a72d8b866a2d7bf20d48 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Sun, 20 Oct 2024 04:07:31 +0000 Subject: [PATCH 065/123] Update sbt to 1.10.3 --- project/build.properties | 2 +- scalafix/project/build.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/project/build.properties b/project/build.properties index 0b699c3052..bc7390601f 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.2 +sbt.version=1.10.3 diff --git a/scalafix/project/build.properties b/scalafix/project/build.properties index 0b699c3052..bc7390601f 100644 --- a/scalafix/project/build.properties +++ b/scalafix/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.2 +sbt.version=1.10.3 From fd1caeeddc6e4294370cb3bbc82c972f6a613403 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 08:06:08 +0000 Subject: [PATCH 066/123] Update sbt-doctest to 0.11.0 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 76f8e1e6d7..bfb4679402 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,7 +2,7 @@ val sbtTypelevelVersion = "0.7.4" addSbtPlugin("org.typelevel" % "sbt-typelevel" % sbtTypelevelVersion) addSbtPlugin("org.typelevel" % "sbt-typelevel-site" % sbtTypelevelVersion) addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") -addSbtPlugin("com.github.tkawachi" % "sbt-doctest" % "0.10.0") +addSbtPlugin("io.github.sbt-doctest" % "sbt-doctest" % "0.11.0") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.5") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.12.0") From 842770ce6720461674b82a62312830d5bb1a6f2d Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:09:58 +0000 Subject: [PATCH 067/123] Update sbt to 1.10.4 --- project/build.properties | 2 +- scalafix/project/build.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/project/build.properties b/project/build.properties index bc7390601f..09feeeed5d 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.3 +sbt.version=1.10.4 diff --git a/scalafix/project/build.properties b/scalafix/project/build.properties index bc7390601f..09feeeed5d 100644 --- a/scalafix/project/build.properties +++ b/scalafix/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.3 +sbt.version=1.10.4 From 80527cfb7a05c0eba32f59c315bbdde006b44d7c Mon Sep 17 00:00:00 2001 From: aluscent Date: Tue, 29 Oct 2024 14:35:21 +0330 Subject: [PATCH 068/123] Fixed issue #4642 --- .../src/main/scala/alleycats/syntax/all.scala | 2 +- .../src/main/scala/alleycats/syntax/extract.scala | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 alleycats-core/src/main/scala/alleycats/syntax/extract.scala diff --git a/alleycats-core/src/main/scala/alleycats/syntax/all.scala b/alleycats-core/src/main/scala/alleycats/syntax/all.scala index 79ef6c6a48..be4a67772e 100644 --- a/alleycats-core/src/main/scala/alleycats/syntax/all.scala +++ b/alleycats-core/src/main/scala/alleycats/syntax/all.scala @@ -21,4 +21,4 @@ package alleycats.syntax -object all extends EmptySyntax with FoldableSyntax +object all extends EmptySyntax with FoldableSyntax with ExtractSyntax diff --git a/alleycats-core/src/main/scala/alleycats/syntax/extract.scala b/alleycats-core/src/main/scala/alleycats/syntax/extract.scala new file mode 100644 index 0000000000..6d1a013a34 --- /dev/null +++ b/alleycats-core/src/main/scala/alleycats/syntax/extract.scala @@ -0,0 +1,12 @@ +package alleycats +package syntax + +import alleycats.Extract + +object extract extends ExtractSyntax + +trait ExtractSyntax { + implicit class ExtractOps[F[_], A](fa: F[A])(implicit ev: Extract[F]) { + def extract(): A = ev.extract(fa) + } +} \ No newline at end of file From 992f72d751a092df9742ca838a9330ea65382220 Mon Sep 17 00:00:00 2001 From: aluscent Date: Tue, 29 Oct 2024 15:09:05 +0330 Subject: [PATCH 069/123] Added header to file --- .../main/scala/alleycats/syntax/extract.scala | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/alleycats-core/src/main/scala/alleycats/syntax/extract.scala b/alleycats-core/src/main/scala/alleycats/syntax/extract.scala index 6d1a013a34..bd5d1823f7 100644 --- a/alleycats-core/src/main/scala/alleycats/syntax/extract.scala +++ b/alleycats-core/src/main/scala/alleycats/syntax/extract.scala @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2015 Typelevel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + package alleycats package syntax From 2c1d7971aa5aa9fbfcffcc46c2015235df1bceb9 Mon Sep 17 00:00:00 2001 From: aluscent Date: Tue, 29 Oct 2024 15:16:12 +0330 Subject: [PATCH 070/123] Formatted using scalafmt --- alleycats-core/src/main/scala/alleycats/syntax/extract.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alleycats-core/src/main/scala/alleycats/syntax/extract.scala b/alleycats-core/src/main/scala/alleycats/syntax/extract.scala index bd5d1823f7..7a4fb8afa0 100644 --- a/alleycats-core/src/main/scala/alleycats/syntax/extract.scala +++ b/alleycats-core/src/main/scala/alleycats/syntax/extract.scala @@ -30,4 +30,4 @@ trait ExtractSyntax { implicit class ExtractOps[F[_], A](fa: F[A])(implicit ev: Extract[F]) { def extract(): A = ev.extract(fa) } -} \ No newline at end of file +} From b9b7e201ac10d3b7a164c57ee0bb511ea45b3ec9 Mon Sep 17 00:00:00 2001 From: Ali Tariverdy <35956849+aluscent@users.noreply.github.com> Date: Sat, 2 Nov 2024 12:52:13 +0330 Subject: [PATCH 071/123] Changing ExtractOps class to value class The reason why I think it could make sense is that: 1. This is a pretty valid use case for value classes in general and allows to save on memory allocations a little bit. 2. Newer syntaxes in Cats-core use this approach a lot, see Applicative syntax for example: Co-authored-by: Sergey Torgashov --- alleycats-core/src/main/scala/alleycats/syntax/extract.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alleycats-core/src/main/scala/alleycats/syntax/extract.scala b/alleycats-core/src/main/scala/alleycats/syntax/extract.scala index 7a4fb8afa0..3ba0697975 100644 --- a/alleycats-core/src/main/scala/alleycats/syntax/extract.scala +++ b/alleycats-core/src/main/scala/alleycats/syntax/extract.scala @@ -27,7 +27,7 @@ import alleycats.Extract object extract extends ExtractSyntax trait ExtractSyntax { - implicit class ExtractOps[F[_], A](fa: F[A])(implicit ev: Extract[F]) { - def extract(): A = ev.extract(fa) + implicit final class ExtractOps[F[_], A](private val fa: F[A]) extends AnyVal { + def extract(implicit ev: Extract[F]): A = ev.extract(fa) } } From af135dc1fdd128bc7c351ef00231f671824c6f63 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 08:05:39 +0000 Subject: [PATCH 072/123] Update sbt-buildinfo to 0.13.0 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index bfb4679402..f2d3a36170 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -5,6 +5,6 @@ addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") addSbtPlugin("io.github.sbt-doctest" % "sbt-doctest" % "0.11.0") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.5") -addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.12.0") +addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.13.0") libraryDependencySchemes += "com.lihaoyi" %% "geny" % VersionScheme.Always From a0e5c54cccc80d37172f0887a45d2cbd9b8317bc Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 00:21:31 +0000 Subject: [PATCH 073/123] Update sbt to 1.10.5 --- project/build.properties | 2 +- scalafix/project/build.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/project/build.properties b/project/build.properties index 09feeeed5d..db1723b086 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.4 +sbt.version=1.10.5 diff --git a/scalafix/project/build.properties b/scalafix/project/build.properties index 09feeeed5d..db1723b086 100644 --- a/scalafix/project/build.properties +++ b/scalafix/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.4 +sbt.version=1.10.5 From 80fdf5cce958adfb576d39705c1159e9170395d0 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Sat, 9 Nov 2024 12:06:42 +0000 Subject: [PATCH 074/123] Update sbt-buildinfo to 0.13.1 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index f2d3a36170..aa73709b53 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -5,6 +5,6 @@ addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") addSbtPlugin("io.github.sbt-doctest" % "sbt-doctest" % "0.11.0") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.5") -addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.13.0") +addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.13.1") libraryDependencySchemes += "com.lihaoyi" %% "geny" % VersionScheme.Always From d1c727874d6809a01d792846ca35a832d3197891 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Thu, 14 Nov 2024 08:06:18 +0000 Subject: [PATCH 075/123] Update auxlib, clib, javalib, nativelib, ... to 0.5.6 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index aa73709b53..efdd41b5c7 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -4,7 +4,7 @@ addSbtPlugin("org.typelevel" % "sbt-typelevel-site" % sbtTypelevelVersion) addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") addSbtPlugin("io.github.sbt-doctest" % "sbt-doctest" % "0.11.0") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") -addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.5") +addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.6") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.13.1") libraryDependencySchemes += "com.lihaoyi" %% "geny" % VersionScheme.Always From 89deb4c87fdea00c5a2fa97e981f714ccda72f59 Mon Sep 17 00:00:00 2001 From: Georgi Krastev Date: Thu, 14 Nov 2024 23:44:50 +0100 Subject: [PATCH 076/123] Use alignWith in alignMergeWith `alignWith` is usually overridden for efficiency --- core/src/main/scala/cats/Align.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/Align.scala b/core/src/main/scala/cats/Align.scala index 9bdc4a7a69..0b871930cc 100644 --- a/core/src/main/scala/cats/Align.scala +++ b/core/src/main/scala/cats/Align.scala @@ -84,7 +84,7 @@ trait Align[F[_]] extends Serializable { * }}} */ def alignMergeWith[A](fa1: F[A], fa2: F[A])(f: (A, A) => A): F[A] = - functor.map(align(fa1, fa2))(_.mergeWith(f)) + alignWith(fa1, fa2)(_.mergeWith(f)) /** * Same as `align`, but forgets from the type that one of the two elements must be present. From 0c7adabe7fb9f96cb1267cf07841d8d80d4b4553 Mon Sep 17 00:00:00 2001 From: Georgi Krastev Date: Fri, 15 Nov 2024 09:57:38 +0100 Subject: [PATCH 077/123] Add consistency law for alignMergeWith --- laws/src/main/scala/cats/laws/AlignLaws.scala | 3 +++ .../src/main/scala/cats/laws/discipline/AlignTests.scala | 9 +++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/laws/src/main/scala/cats/laws/AlignLaws.scala b/laws/src/main/scala/cats/laws/AlignLaws.scala index eb83c47241..490e266e75 100644 --- a/laws/src/main/scala/cats/laws/AlignLaws.scala +++ b/laws/src/main/scala/cats/laws/AlignLaws.scala @@ -45,6 +45,9 @@ trait AlignLaws[F[_]] { def alignWithConsistent[A, B, C](fa: F[A], fb: F[B], f: A Ior B => C): IsEq[F[C]] = fa.alignWith(fb)(f) <-> fa.align(fb).map(f) + def alignMergeWithConsistent[A](fa1: F[A], fa2: F[A], f: (A, A) => A): IsEq[F[A]] = + fa1.alignMergeWith(fa2)(f) <-> fa1.align(fa2).map(_.mergeWith(f)) + private def assoc[A, B, C](x: Ior[A, Ior[B, C]]): Ior[Ior[A, B], C] = x match { case Left(a) => Left(Left(a)) diff --git a/laws/src/main/scala/cats/laws/discipline/AlignTests.scala b/laws/src/main/scala/cats/laws/discipline/AlignTests.scala index 4b4a37bb60..f640349b74 100644 --- a/laws/src/main/scala/cats/laws/discipline/AlignTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/AlignTests.scala @@ -54,12 +54,9 @@ trait AlignTests[F[_]] extends Laws { name = "align", parent = None, "align associativity" -> forAll(laws.alignAssociativity[A, B, C] _), - "align homomorphism" -> forAll { (fa: F[A], fb: F[B], f: A => C, g: B => D) => - laws.alignHomomorphism[A, B, C, D](fa, fb, f, g) - }, - "alignWith consistent" -> forAll { (fa: F[A], fb: F[B], f: A Ior B => C) => - laws.alignWithConsistent[A, B, C](fa, fb, f) - } + "align homomorphism" -> forAll(laws.alignHomomorphism[A, B, C, D] _), + "alignWith consistent" -> forAll(laws.alignWithConsistent[A, B, C] _), + "alignMergeWith consistent" -> forAll(laws.alignMergeWithConsistent[A] _) ) } From 66137d80ab22cf2e0661626871ba02fde600445d Mon Sep 17 00:00:00 2001 From: Laurence Warne Date: Tue, 19 Nov 2024 18:55:29 +0000 Subject: [PATCH 078/123] Fix alleycats set functor ambiguous implicits --- .../src/main/scala/alleycats/std/set.scala | 28 +++++++++++-------- .../test/scala/alleycats/tests/SetSuite.scala | 5 +++- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/alleycats-core/src/main/scala/alleycats/std/set.scala b/alleycats-core/src/main/scala/alleycats/std/set.scala index 9421e69aac..1e5ed6934f 100644 --- a/alleycats-core/src/main/scala/alleycats/std/set.scala +++ b/alleycats-core/src/main/scala/alleycats/std/set.scala @@ -30,7 +30,20 @@ import scala.annotation.tailrec object set extends SetInstances @suppressUnusedImportWarningForScalaVersionSpecific -trait SetInstances { +trait SetInstances extends SetInstances0 { + + implicit val alleyCatsSetTraverseFilter: TraverseFilter[Set] = + new TraverseFilter[Set] { + val traverse: Traverse[Set] = alleyCatsSetTraverse + + def traverseFilter[G[_], A, B](fa: Set[A])(f: A => G[Option[B]])(implicit G: Applicative[G]): G[Set[B]] = + traverse + .foldRight(fa, Eval.now(G.pure(Set.empty[B])))((x, xse) => G.map2Eval(f(x), xse)((i, o) => i.fold(o)(o + _))) + .value + } +} + +private[std] trait SetInstances0 extends SetInstances1 { // Monad advertises parametricity, but Set relies on using // universal hash codes and equality, which hurts our ability to // rely on free theorems. @@ -99,6 +112,9 @@ trait SetInstances { override def appendK[A](fa: Set[A], a: A): Set[A] = fa + a } +} + +private[std] trait SetInstances1 { // Since iteration order is not guaranteed for sets, folds and other // traversals may produce different results for input sets which @@ -172,14 +188,4 @@ trait SetInstances { override def collectFirstSome[A, B](fa: Set[A])(f: A => Option[B]): Option[B] = fa.collectFirst(Function.unlift(f)) } - - implicit val alleyCatsSetTraverseFilter: TraverseFilter[Set] = - new TraverseFilter[Set] { - val traverse: Traverse[Set] = alleyCatsSetTraverse - - def traverseFilter[G[_], A, B](fa: Set[A])(f: A => G[Option[B]])(implicit G: Applicative[G]): G[Set[B]] = - traverse - .foldRight(fa, Eval.now(G.pure(Set.empty[B])))((x, xse) => G.map2Eval(f(x), xse)((i, o) => i.fold(o)(o + _))) - .value - } } diff --git a/alleycats-laws/shared/src/test/scala/alleycats/tests/SetSuite.scala b/alleycats-laws/shared/src/test/scala/alleycats/tests/SetSuite.scala index c71091bc78..3619111fef 100644 --- a/alleycats-laws/shared/src/test/scala/alleycats/tests/SetSuite.scala +++ b/alleycats-laws/shared/src/test/scala/alleycats/tests/SetSuite.scala @@ -28,7 +28,7 @@ import cats.instances.all._ import cats.kernel.laws.discipline.SerializableTests import cats.laws.discipline.SemigroupalTests.Isomorphisms import cats.laws.discipline.arbitrary._ -import cats.laws.discipline.{AlternativeTests, ShortCircuitingTests, TraverseFilterTests} +import cats.laws.discipline.{AlternativeTests, FunctorTests, ShortCircuitingTests, TraverseFilterTests} class SetSuite extends AlleycatsSuite { implicit val iso: Isomorphisms[Set] = Isomorphisms.invariant[Set](alleyCatsStdSetMonad) @@ -40,6 +40,9 @@ class SetSuite extends AlleycatsSuite { checkAll("TraverseFilter[Set]", TraverseFilterTests[Set].traverseFilter[Int, Int, Int]) checkAll("Set[Int]", AlternativeTests[Set].alternative[Int, Int, Int]) + + checkAll("Functor[Int]", FunctorTests[Set].functor[Int, Int, Int]) + checkAll("Alternative[Set]", SerializableTests.serializable(Alternative[Set])) checkAll("Set[Int]", ShortCircuitingTests[Set].traverseFilter[Int]) From 1ed210dc929a93105f7a3ec7a72d76f25e007a38 Mon Sep 17 00:00:00 2001 From: Alexandr Chigrinets Date: Wed, 20 Nov 2024 22:34:29 +0300 Subject: [PATCH 079/123] Change IPONWEB to Criteo in ADOPTERS.md --- ADOPTERS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ADOPTERS.md b/ADOPTERS.md index dcad9bef9a..9b78979403 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -28,6 +28,7 @@ And if you can, consider [supporting us](https://opencollective.com/typelevel). - [Colisweb](https://www.colisweb.com/) - [CompStak](https://compstak.com) - [Coya](https://coya.com/) +- [Criteo](https://www.criteo.com/) - [Datum Brain](https://datumbrain.com/) - [Disney](https://disney.com/) - [Dripower LTD](https://zd.drip.im) @@ -58,7 +59,6 @@ And if you can, consider [supporting us](https://opencollective.com/typelevel). - [innFactory GmbH](https://www.innfactory.de/) - [Intent HQ](https://www.intenthq.com/) - [iofod](https://www.iofod.com/) -- [IPONWEB](https://www.iponweb.com/) - [Iterators](https://www.iteratorshq.com/) - [ITV](https://www.itv.com/) - [Kaluza](https://www.kaluza.com) From 8496e12dc9f4b03f119c4111237f87d35c79d020 Mon Sep 17 00:00:00 2001 From: Laurence Warne Date: Tue, 26 Nov 2024 16:48:03 +0000 Subject: [PATCH 080/123] Mark old instances as deprecated to preserve bin compat --- .../src/main/scala/alleycats/std/set.scala | 41 ++++++++----------- .../test/scala/alleycats/tests/SetSuite.scala | 2 +- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/alleycats-core/src/main/scala/alleycats/std/set.scala b/alleycats-core/src/main/scala/alleycats/std/set.scala index 1e5ed6934f..a9231f0b3a 100644 --- a/alleycats-core/src/main/scala/alleycats/std/set.scala +++ b/alleycats-core/src/main/scala/alleycats/std/set.scala @@ -30,20 +30,14 @@ import scala.annotation.tailrec object set extends SetInstances @suppressUnusedImportWarningForScalaVersionSpecific -trait SetInstances extends SetInstances0 { +trait SetInstances { + @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") + val alleyCatsSetTraverse: Traverse[Set] = alleycatsStdInstancesForSet + @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") + val alleyCatsStdSetMonad: Monad[Set] with Alternative[Set] = alleycatsStdInstancesForSet + @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") + val alleyCatsSetTraverseFilter: TraverseFilter[Set] = alleycatsStdInstancesForSet - implicit val alleyCatsSetTraverseFilter: TraverseFilter[Set] = - new TraverseFilter[Set] { - val traverse: Traverse[Set] = alleyCatsSetTraverse - - def traverseFilter[G[_], A, B](fa: Set[A])(f: A => G[Option[B]])(implicit G: Applicative[G]): G[Set[B]] = - traverse - .foldRight(fa, Eval.now(G.pure(Set.empty[B])))((x, xse) => G.map2Eval(f(x), xse)((i, o) => i.fold(o)(o + _))) - .value - } -} - -private[std] trait SetInstances0 extends SetInstances1 { // Monad advertises parametricity, but Set relies on using // universal hash codes and equality, which hurts our ability to // rely on free theorems. @@ -68,8 +62,16 @@ private[std] trait SetInstances0 extends SetInstances1 { // If we accept Monad for Set, we can also have Alternative, as // Alternative only requires MonoidK (already accepted by cats-core) and // the Applicative that comes from Monad. - implicit val alleyCatsStdSetMonad: Monad[Set] with Alternative[Set] = - new Monad[Set] with Alternative[Set] { + implicit def alleycatsStdInstancesForSet + : Monad[Set] with Alternative[Set] with Traverse[Set] with TraverseFilter[Set] = + new Monad[Set] with Alternative[Set] with Traverse[Set] with TraverseFilter[Set] { + val traverse: Traverse[Set] = this + + def traverseFilter[G[_], A, B](fa: Set[A])(f: A => G[Option[B]])(implicit G: Applicative[G]): G[Set[B]] = + traverse + .foldRight(fa, Eval.now(G.pure(Set.empty[B])))((x, xse) => G.map2Eval(f(x), xse)((i, o) => i.fold(o)(o + _))) + .value + def pure[A](a: A): Set[A] = Set(a) override def map[A, B](fa: Set[A])(f: A => B): Set[B] = fa.map(f) def flatMap[A, B](fa: Set[A])(f: A => Set[B]): Set[B] = fa.flatMap(f) @@ -111,16 +113,7 @@ private[std] trait SetInstances0 extends SetInstances1 { override def prependK[A](a: A, fa: Set[A]): Set[A] = fa + a override def appendK[A](fa: Set[A], a: A): Set[A] = fa + a - } -} - -private[std] trait SetInstances1 { - // Since iteration order is not guaranteed for sets, folds and other - // traversals may produce different results for input sets which - // appear to be the same. - implicit val alleyCatsSetTraverse: Traverse[Set] = - new Traverse[Set] { def foldLeft[A, B](fa: Set[A], b: B)(f: (B, A) => B): B = fa.foldLeft(b)(f) def foldRight[A, B](fa: Set[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = diff --git a/alleycats-laws/shared/src/test/scala/alleycats/tests/SetSuite.scala b/alleycats-laws/shared/src/test/scala/alleycats/tests/SetSuite.scala index 3619111fef..8b926b34c9 100644 --- a/alleycats-laws/shared/src/test/scala/alleycats/tests/SetSuite.scala +++ b/alleycats-laws/shared/src/test/scala/alleycats/tests/SetSuite.scala @@ -31,7 +31,7 @@ import cats.laws.discipline.arbitrary._ import cats.laws.discipline.{AlternativeTests, FunctorTests, ShortCircuitingTests, TraverseFilterTests} class SetSuite extends AlleycatsSuite { - implicit val iso: Isomorphisms[Set] = Isomorphisms.invariant[Set](alleyCatsStdSetMonad) + implicit val iso: Isomorphisms[Set] = Isomorphisms.invariant[Set](alleycatsStdInstancesForSet) checkAll("FlatMapRec[Set]", FlatMapRecTests[Set].tailRecM[Int]) From 9f70fce414b0e6d20d28ec3c58b3babfc5ea7da8 Mon Sep 17 00:00:00 2001 From: Laurence Warne Date: Thu, 28 Nov 2024 18:08:31 +0000 Subject: [PATCH 081/123] Use val and define deprecated aliases after --- .../src/main/scala/alleycats/std/set.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/alleycats-core/src/main/scala/alleycats/std/set.scala b/alleycats-core/src/main/scala/alleycats/std/set.scala index a9231f0b3a..bff022b424 100644 --- a/alleycats-core/src/main/scala/alleycats/std/set.scala +++ b/alleycats-core/src/main/scala/alleycats/std/set.scala @@ -31,13 +31,6 @@ object set extends SetInstances @suppressUnusedImportWarningForScalaVersionSpecific trait SetInstances { - @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") - val alleyCatsSetTraverse: Traverse[Set] = alleycatsStdInstancesForSet - @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") - val alleyCatsStdSetMonad: Monad[Set] with Alternative[Set] = alleycatsStdInstancesForSet - @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") - val alleyCatsSetTraverseFilter: TraverseFilter[Set] = alleycatsStdInstancesForSet - // Monad advertises parametricity, but Set relies on using // universal hash codes and equality, which hurts our ability to // rely on free theorems. @@ -62,7 +55,7 @@ trait SetInstances { // If we accept Monad for Set, we can also have Alternative, as // Alternative only requires MonoidK (already accepted by cats-core) and // the Applicative that comes from Monad. - implicit def alleycatsStdInstancesForSet + implicit val alleycatsStdInstancesForSet : Monad[Set] with Alternative[Set] with Traverse[Set] with TraverseFilter[Set] = new Monad[Set] with Alternative[Set] with Traverse[Set] with TraverseFilter[Set] { val traverse: Traverse[Set] = this @@ -181,4 +174,11 @@ trait SetInstances { override def collectFirstSome[A, B](fa: Set[A])(f: A => Option[B]): Option[B] = fa.collectFirst(Function.unlift(f)) } + + @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") + val alleyCatsSetTraverse: Traverse[Set] = alleycatsStdInstancesForSet + @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") + val alleyCatsStdSetMonad: Monad[Set] with Alternative[Set] = alleycatsStdInstancesForSet + @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") + val alleyCatsSetTraverseFilter: TraverseFilter[Set] = alleycatsStdInstancesForSet } From ca432b24f8d4673de1b311750f15cbf3b8dd953e Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Sat, 30 Nov 2024 08:07:39 +0000 Subject: [PATCH 082/123] Update sbt, scripted-plugin to 1.10.6 --- project/build.properties | 2 +- scalafix/project/build.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/project/build.properties b/project/build.properties index db1723b086..e88a0d817d 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.5 +sbt.version=1.10.6 diff --git a/scalafix/project/build.properties b/scalafix/project/build.properties index db1723b086..e88a0d817d 100644 --- a/scalafix/project/build.properties +++ b/scalafix/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.5 +sbt.version=1.10.6 From 686ba738c8171fff6c59dd8e921380f3e98fe499 Mon Sep 17 00:00:00 2001 From: xuwei-k <6b656e6a69@gmail.com> Date: Wed, 6 Nov 2024 12:58:18 +0900 Subject: [PATCH 083/123] use & instead of with --- .../src/main/scala/alleycats/std/set.scala | 2 +- .../cats/ScalaVersionSpecificInstances.scala | 6 ++-- .../cats/data/NonEmptyLazyList.scala | 9 +++-- .../scala-2.13+/cats/data/ZipLazyList.scala | 2 +- .../scala-2.13+/cats/data/ZipStream.scala | 2 +- .../scala-2.13+/cats/instances/arraySeq.scala | 4 +-- .../scala-2.13+/cats/instances/lazyList.scala | 2 +- .../scala-2.13+/cats/instances/stream.scala | 2 +- core/src/main/scala/cats/Eval.scala | 2 +- core/src/main/scala/cats/Invariant.scala | 17 +++++----- .../main/scala/cats/UnorderedFoldable.scala | 2 +- core/src/main/scala/cats/arrow/Compose.scala | 4 +-- core/src/main/scala/cats/data/AndThen.scala | 2 +- core/src/main/scala/cats/data/Chain.scala | 4 +-- .../main/scala/cats/data/IndexedStateT.scala | 2 +- core/src/main/scala/cats/data/Kleisli.scala | 2 +- core/src/main/scala/cats/data/Newtype.scala | 2 +- core/src/main/scala/cats/data/Newtype2.scala | 2 +- .../main/scala/cats/data/NonEmptyChain.scala | 18 +++++----- .../main/scala/cats/data/NonEmptyList.scala | 10 +++--- .../scala/cats/data/NonEmptyMapImpl.scala | 4 +-- .../main/scala/cats/data/NonEmptySeq.scala | 8 ++--- .../main/scala/cats/data/NonEmptySet.scala | 2 +- .../main/scala/cats/data/NonEmptyVector.scala | 14 ++++---- .../main/scala/cats/instances/either.scala | 2 +- .../main/scala/cats/instances/function.scala | 2 +- .../main/scala/cats/instances/future.scala | 2 +- core/src/main/scala/cats/instances/list.scala | 2 +- core/src/main/scala/cats/instances/map.scala | 2 +- .../main/scala/cats/instances/option.scala | 9 ++--- .../cats/instances/partialFunction.scala | 4 +-- .../src/main/scala/cats/instances/queue.scala | 5 ++- core/src/main/scala/cats/instances/seq.scala | 3 +- core/src/main/scala/cats/instances/set.scala | 2 +- .../main/scala/cats/instances/sortedMap.scala | 4 +-- .../main/scala/cats/instances/sortedSet.scala | 2 +- .../main/scala/cats/instances/tailrec.scala | 4 +-- core/src/main/scala/cats/instances/try.scala | 2 +- .../src/main/scala/cats/instances/tuple.scala | 2 +- .../main/scala/cats/instances/vector.scala | 2 +- core/src/main/scala/cats/package.scala | 2 +- .../cats/kernel/laws/EnumerableLaws.scala | 4 +-- .../scala/cats/kernel/laws/LawTests.scala | 2 +- .../main/scala/cats/kernel/Comparison.scala | 2 +- kernel/src/main/scala/cats/kernel/Eq.scala | 34 +++++++++---------- kernel/src/main/scala/cats/kernel/Order.scala | 2 +- .../main/scala/cats/kernel/Semigroup.scala | 2 +- .../instances/BigDecimalInstances.scala | 2 +- .../kernel/instances/BigIntInstances.scala | 2 +- .../kernel/instances/BitSetInstances.scala | 2 +- .../kernel/instances/BooleanInstances.scala | 2 +- .../cats/kernel/instances/ByteInstances.scala | 2 +- .../cats/kernel/instances/CharInstances.scala | 2 +- .../kernel/instances/DeadlineInstances.scala | 2 +- .../kernel/instances/DoubleInstances.scala | 2 +- .../kernel/instances/DurationInstances.scala | 2 +- .../instances/FiniteDurationInstances.scala | 7 ++-- .../kernel/instances/FloatInstances.scala | 2 +- .../cats/kernel/instances/IntInstances.scala | 2 +- .../cats/kernel/instances/LongInstances.scala | 2 +- .../kernel/instances/ShortInstances.scala | 2 +- .../kernel/instances/StringInstances.scala | 2 +- .../kernel/instances/SymbolInstances.scala | 2 +- .../cats/kernel/instances/UUIDInstances.scala | 2 +- .../cats/kernel/instances/UnitInstances.scala | 4 +-- .../scala/cats/laws/discipline/MiniInt.scala | 2 +- .../cats/tests/AlgebraInvariantSuite.scala | 3 +- 67 files changed, 128 insertions(+), 141 deletions(-) diff --git a/alleycats-core/src/main/scala/alleycats/std/set.scala b/alleycats-core/src/main/scala/alleycats/std/set.scala index 9421e69aac..c113d1f985 100644 --- a/alleycats-core/src/main/scala/alleycats/std/set.scala +++ b/alleycats-core/src/main/scala/alleycats/std/set.scala @@ -55,7 +55,7 @@ trait SetInstances { // If we accept Monad for Set, we can also have Alternative, as // Alternative only requires MonoidK (already accepted by cats-core) and // the Applicative that comes from Monad. - implicit val alleyCatsStdSetMonad: Monad[Set] with Alternative[Set] = + implicit val alleyCatsStdSetMonad: Monad[Set] & Alternative[Set] = new Monad[Set] with Alternative[Set] { def pure[A](a: A): Set[A] = Set(a) override def map[A, B](fa: Set[A])(f: A => B): Set[B] = fa.map(f) diff --git a/core/src/main/scala-2.13+/cats/ScalaVersionSpecificInstances.scala b/core/src/main/scala-2.13+/cats/ScalaVersionSpecificInstances.scala index 673f0eac11..ca72612675 100644 --- a/core/src/main/scala-2.13+/cats/ScalaVersionSpecificInstances.scala +++ b/core/src/main/scala-2.13+/cats/ScalaVersionSpecificInstances.scala @@ -67,13 +67,13 @@ private[cats] trait ScalaVersionSpecificParallelInstances { private[cats] trait ScalaVersionSpecificInvariantInstances { @deprecated("Use catsInstancesForLazyList", "3.0.0") - implicit def catsInstancesForStream: Monad[Stream] with Alternative[Stream] with CoflatMap[Stream] = + implicit def catsInstancesForStream: Monad[Stream] & Alternative[Stream] & CoflatMap[Stream] = cats.instances.stream.catsStdInstancesForStream - implicit def catsInstancesForLazyList: Monad[LazyList] with Alternative[LazyList] with CoflatMap[LazyList] = + implicit def catsInstancesForLazyList: Monad[LazyList] & Alternative[LazyList] & CoflatMap[LazyList] = cats.instances.lazyList.catsStdInstancesForLazyList - implicit def catsInstancesForArraySeq: Monad[ArraySeq] with Alternative[ArraySeq] with CoflatMap[ArraySeq] = + implicit def catsInstancesForArraySeq: Monad[ArraySeq] & Alternative[ArraySeq] & CoflatMap[ArraySeq] = cats.instances.arraySeq.catsStdInstancesForArraySeq } diff --git a/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala b/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala index 6faf08c5b6..9e0547ef29 100644 --- a/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala +++ b/core/src/main/scala-2.13+/cats/data/NonEmptyLazyList.scala @@ -38,7 +38,7 @@ object NonEmptyLazyList extends NonEmptyLazyListInstances { private[data] type Base private[data] trait Tag extends Any /* aliased in data package as NonEmptyLazyList */ - type Type[+A] <: Base with Tag + type Type[+A] <: Base & Tag private[data] def create[A](s: LazyList[A]): Type[A] = s.asInstanceOf[Type[A]] @@ -510,10 +510,9 @@ class NonEmptyLazyListOps[A](private val value: NonEmptyLazyList[A]) sealed abstract private[data] class NonEmptyLazyListInstances extends NonEmptyLazyListInstances1 { - implicit val catsDataInstancesForNonEmptyLazyList: Bimonad[NonEmptyLazyList] - with NonEmptyTraverse[NonEmptyLazyList] - with NonEmptyAlternative[NonEmptyLazyList] - with Align[NonEmptyLazyList] = + implicit val catsDataInstancesForNonEmptyLazyList: Bimonad[NonEmptyLazyList] & NonEmptyTraverse[ + NonEmptyLazyList + ] & NonEmptyAlternative[NonEmptyLazyList] & Align[NonEmptyLazyList] = new AbstractNonEmptyInstances[LazyList, NonEmptyLazyList] with Align[NonEmptyLazyList] { def extract[A](fa: NonEmptyLazyList[A]): A = fa.head diff --git a/core/src/main/scala-2.13+/cats/data/ZipLazyList.scala b/core/src/main/scala-2.13+/cats/data/ZipLazyList.scala index 516054a625..0f5d552636 100644 --- a/core/src/main/scala-2.13+/cats/data/ZipLazyList.scala +++ b/core/src/main/scala-2.13+/cats/data/ZipLazyList.scala @@ -28,7 +28,7 @@ object ZipLazyList { def apply[A](value: LazyList[A]): ZipLazyList[A] = new ZipLazyList(value) - implicit val catsDataAlternativeForZipLazyList: Alternative[ZipLazyList] with CommutativeApplicative[ZipLazyList] = + implicit val catsDataAlternativeForZipLazyList: Alternative[ZipLazyList] & CommutativeApplicative[ZipLazyList] = new Alternative[ZipLazyList] with CommutativeApplicative[ZipLazyList] { def pure[A](x: A): ZipLazyList[A] = new ZipLazyList(LazyList.continually(x)) diff --git a/core/src/main/scala-2.13+/cats/data/ZipStream.scala b/core/src/main/scala-2.13+/cats/data/ZipStream.scala index 576a75f007..1f80ceef78 100644 --- a/core/src/main/scala-2.13+/cats/data/ZipStream.scala +++ b/core/src/main/scala-2.13+/cats/data/ZipStream.scala @@ -30,7 +30,7 @@ object ZipStream { def apply[A](value: Stream[A]): ZipStream[A] = new ZipStream(value) - implicit val catsDataAlternativeForZipStream: Alternative[ZipStream] with CommutativeApplicative[ZipStream] = + implicit val catsDataAlternativeForZipStream: Alternative[ZipStream] & CommutativeApplicative[ZipStream] = new Alternative[ZipStream] with CommutativeApplicative[ZipStream] { def pure[A](x: A): ZipStream[A] = new ZipStream(Stream.continually(x)) diff --git a/core/src/main/scala-2.13+/cats/instances/arraySeq.scala b/core/src/main/scala-2.13+/cats/instances/arraySeq.scala index f41a781ad6..e0b3c932cd 100644 --- a/core/src/main/scala-2.13+/cats/instances/arraySeq.scala +++ b/core/src/main/scala-2.13+/cats/instances/arraySeq.scala @@ -29,7 +29,7 @@ import scala.collection.mutable.Builder trait ArraySeqInstances extends cats.kernel.instances.ArraySeqInstances { implicit def catsStdInstancesForArraySeq - : Traverse[ArraySeq] with Monad[ArraySeq] with Alternative[ArraySeq] with CoflatMap[ArraySeq] with Align[ArraySeq] = + : Traverse[ArraySeq] & Monad[ArraySeq] & Alternative[ArraySeq] & CoflatMap[ArraySeq] & Align[ArraySeq] = ArraySeqInstances.stdInstances implicit def catsStdTraverseFilterForArraySeq: TraverseFilter[ArraySeq] = @@ -41,7 +41,7 @@ trait ArraySeqInstances extends cats.kernel.instances.ArraySeqInstances { private[cats] object ArraySeqInstances { final private val stdInstances - : Traverse[ArraySeq] with Monad[ArraySeq] with Alternative[ArraySeq] with CoflatMap[ArraySeq] with Align[ArraySeq] = + : Traverse[ArraySeq] & Monad[ArraySeq] & Alternative[ArraySeq] & CoflatMap[ArraySeq] & Align[ArraySeq] = new Traverse[ArraySeq] with Monad[ArraySeq] with Alternative[ArraySeq] diff --git a/core/src/main/scala-2.13+/cats/instances/lazyList.scala b/core/src/main/scala-2.13+/cats/instances/lazyList.scala index 6b3069d5e3..3140de76e1 100644 --- a/core/src/main/scala-2.13+/cats/instances/lazyList.scala +++ b/core/src/main/scala-2.13+/cats/instances/lazyList.scala @@ -34,7 +34,7 @@ import scala.annotation.tailrec trait LazyListInstances extends cats.kernel.instances.LazyListInstances { implicit val catsStdInstancesForLazyList - : Traverse[LazyList] with Alternative[LazyList] with Monad[LazyList] with CoflatMap[LazyList] with Align[LazyList] = + : Traverse[LazyList] & Alternative[LazyList] & Monad[LazyList] & CoflatMap[LazyList] & Align[LazyList] = new Traverse[LazyList] with Alternative[LazyList] with Monad[LazyList] diff --git a/core/src/main/scala-2.13+/cats/instances/stream.scala b/core/src/main/scala-2.13+/cats/instances/stream.scala index b451f09c37..c011caae7a 100644 --- a/core/src/main/scala-2.13+/cats/instances/stream.scala +++ b/core/src/main/scala-2.13+/cats/instances/stream.scala @@ -33,7 +33,7 @@ trait StreamInstances extends cats.kernel.instances.StreamInstances { @deprecated("Use cats.instances.lazyList", "2.0.0-RC2") implicit val catsStdInstancesForStream - : Traverse[Stream] with Alternative[Stream] with Monad[Stream] with CoflatMap[Stream] with Align[Stream] = + : Traverse[Stream] & Alternative[Stream] & Monad[Stream] & CoflatMap[Stream] & Align[Stream] = new Traverse[Stream] with Alternative[Stream] with Monad[Stream] with CoflatMap[Stream] with Align[Stream] { def empty[A]: Stream[A] = Stream.Empty diff --git a/core/src/main/scala/cats/Eval.scala b/core/src/main/scala/cats/Eval.scala index 813537e2e0..83e387bc08 100644 --- a/core/src/main/scala/cats/Eval.scala +++ b/core/src/main/scala/cats/Eval.scala @@ -389,7 +389,7 @@ object Eval extends EvalInstances { sealed abstract private[cats] class EvalInstances extends EvalInstances0 { - implicit val catsBimonadForEval: Bimonad[Eval] with CommutativeMonad[Eval] = + implicit val catsBimonadForEval: Bimonad[Eval] & CommutativeMonad[Eval] = new Bimonad[Eval] with StackSafeMonad[Eval] with CommutativeMonad[Eval] { override def map[A, B](fa: Eval[A])(f: A => B): Eval[B] = fa.map(f) def pure[A](a: A): Eval[A] = Now(a) diff --git a/core/src/main/scala/cats/Invariant.scala b/core/src/main/scala/cats/Invariant.scala index 2728fdd767..ddc31ec266 100644 --- a/core/src/main/scala/cats/Invariant.scala +++ b/core/src/main/scala/cats/Invariant.scala @@ -124,8 +124,7 @@ trait Invariant[F[_]] extends Serializable { self => @suppressUnusedImportWarningForScalaVersionSpecific object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantInstances0 { - implicit def catsInstancesForId - : Distributive[Id] with Bimonad[Id] with CommutativeMonad[Id] with NonEmptyTraverse[Id] = + implicit def catsInstancesForId: Distributive[Id] & Bimonad[Id] & CommutativeMonad[Id] & NonEmptyTraverse[Id] = cats.catsInstancesForId @deprecated("Added for bincompat", "2.8.0") @targetName3("catsInstancesForId") @@ -134,13 +133,13 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn implicit def catsMonadErrorForEither[A]: MonadError[Either[A, *], A] = cats.instances.either.catsStdInstancesForEither[A] implicit def catsInstancesForOption - : MonadError[Option, Unit] with Alternative[Option] with CoflatMap[Option] with CommutativeMonad[Option] = + : MonadError[Option, Unit] & Alternative[Option] & CoflatMap[Option] & CommutativeMonad[Option] = cats.instances.option.catsStdInstancesForOption - implicit def catsInstancesForList: Monad[List] with Alternative[List] with CoflatMap[List] = + implicit def catsInstancesForList: Monad[List] & Alternative[List] & CoflatMap[List] = cats.instances.list.catsStdInstancesForList - implicit def catsInstancesForVector: Monad[Vector] with Alternative[Vector] with CoflatMap[Vector] = + implicit def catsInstancesForVector: Monad[Vector] & Alternative[Vector] & CoflatMap[Vector] = cats.instances.vector.catsStdInstancesForVector - implicit def catsInstancesForQueue: Monad[Queue] with Alternative[Queue] with CoflatMap[Queue] = + implicit def catsInstancesForQueue: Monad[Queue] & Alternative[Queue] & CoflatMap[Queue] = cats.instances.queue.catsStdInstancesForQueue implicit def catsMonadForTailRec: Monad[TailRec] = cats.instances.tailRec.catsInstancesForTailRec @@ -152,7 +151,7 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn cats.instances.function.catsStdContravariantMonoidalForFunction1[R] implicit def catsFunctorForPair: Functor[λ[P => (P, P)]] = cats.instances.tuple.catsDataFunctorForPair - implicit def catsInstancesForTry: MonadThrow[Try] with CoflatMap[Try] = + implicit def catsInstancesForTry: MonadThrow[Try] & CoflatMap[Try] = cats.instances.try_.catsStdInstancesForTry /** @@ -166,7 +165,7 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn */ implicit def catsInstancesForFuture(implicit ec: ExecutionContext - ): MonadThrow[Future] with CoflatMap[Future] = + ): MonadThrow[Future] & CoflatMap[Future] = cats.instances.future.catsStdInstancesForFuture(ec) implicit def catsContravariantMonoidalForOrder: ContravariantMonoidal[Order] = @@ -339,7 +338,7 @@ private trait InvariantInstances1 extends InvariantInstances2 { private[cats] trait InvariantInstances2 extends cats.instances.NTupleMonadInstances with TupleInstances0 { implicit def catsApplicativeForArrow[F[_, _], A](implicit F: Arrow[F]): Applicative[F[A, *]] = new ArrowApplicative[F, A](F) - implicit def catsInstancesForSeq: Monad[Seq] with Alternative[Seq] with CoflatMap[Seq] = + implicit def catsInstancesForSeq: Monad[Seq] & Alternative[Seq] & CoflatMap[Seq] = cats.instances.seq.catsStdInstancesForSeq } diff --git a/core/src/main/scala/cats/UnorderedFoldable.scala b/core/src/main/scala/cats/UnorderedFoldable.scala index da17638d3a..f903b24882 100644 --- a/core/src/main/scala/cats/UnorderedFoldable.scala +++ b/core/src/main/scala/cats/UnorderedFoldable.scala @@ -165,7 +165,7 @@ object UnorderedFoldable implicit def catsTraverseForTry: Traverse[Try] = cats.instances.try_.catsStdInstancesForTry @deprecated("Use catsStdInstancesForTuple2 in cats.instances.NTupleMonadInstances", "2.4.0") - def catsInstancesForTuple[A]: Traverse[(A, *)] with Reducible[(A, *)] = + def catsInstancesForTuple[A]: Traverse[(A, *)] & Reducible[(A, *)] = cats.instances.tuple.catsStdInstancesForTuple2[A] /** diff --git a/core/src/main/scala/cats/arrow/Compose.scala b/core/src/main/scala/cats/arrow/Compose.scala index d62e7d72e6..d39648161e 100644 --- a/core/src/main/scala/cats/arrow/Compose.scala +++ b/core/src/main/scala/cats/arrow/Compose.scala @@ -53,11 +53,11 @@ trait Compose[F[_, _]] extends Serializable { self => } object Compose { - implicit def catsInstancesForFunction1: ArrowChoice[Function1] with CommutativeArrow[Function1] = + implicit def catsInstancesForFunction1: ArrowChoice[Function1] & CommutativeArrow[Function1] = cats.instances.function.catsStdInstancesForFunction1 implicit def catsComposeForMap: Compose[Map] = cats.instances.map.catsStdComposeForMap - implicit def catsInstancesForPartialFunction: ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] = + implicit def catsInstancesForPartialFunction: ArrowChoice[PartialFunction] & CommutativeArrow[PartialFunction] = cats.instances.partialFunction.catsStdInstancesForPartialFunction /** diff --git a/core/src/main/scala/cats/data/AndThen.scala b/core/src/main/scala/cats/data/AndThen.scala index e7b42bb149..9081968b68 100644 --- a/core/src/main/scala/cats/data/AndThen.scala +++ b/core/src/main/scala/cats/data/AndThen.scala @@ -310,7 +310,7 @@ abstract private[data] class AndThenInstances0 extends AndThenInstances1 { * [[cats.arrow.CommutativeArrow CommutativeArrow]] instances * for [[AndThen]]. */ - implicit val catsDataArrowForAndThen: ArrowChoice[AndThen] with CommutativeArrow[AndThen] = + implicit val catsDataArrowForAndThen: ArrowChoice[AndThen] & CommutativeArrow[AndThen] = new ArrowChoice[AndThen] with CommutativeArrow[AndThen] { // Piggybacking on the instance for Function1 private[this] val fn1 = instances.all.catsStdInstancesForFunction1 diff --git a/core/src/main/scala/cats/data/Chain.scala b/core/src/main/scala/cats/data/Chain.scala index 2248a562ea..5e8a90e85d 100644 --- a/core/src/main/scala/cats/data/Chain.scala +++ b/core/src/main/scala/cats/data/Chain.scala @@ -1203,7 +1203,7 @@ sealed abstract private[data] class ChainInstances extends ChainInstances1 { implicit def catsDataMonoidForChain[A]: Monoid[Chain[A]] = theMonoid.asInstanceOf[Monoid[Chain[A]]] implicit val catsDataInstancesForChain - : Traverse[Chain] with Alternative[Chain] with Monad[Chain] with CoflatMap[Chain] with Align[Chain] = + : Traverse[Chain] & Alternative[Chain] & Monad[Chain] & CoflatMap[Chain] & Align[Chain] = new Traverse[Chain] with Alternative[Chain] with Monad[Chain] with CoflatMap[Chain] with Align[Chain] { def foldLeft[A, B](fa: Chain[A], b: B)(f: (B, A) => B): B = fa.foldLeft(b)(f) @@ -1357,7 +1357,7 @@ sealed abstract private[data] class ChainInstances extends ChainInstances1 { } implicit val catsDataTraverseFilterForChain: TraverseFilter[Chain] = new TraverseFilter[Chain] { - def traverse: Traverse[Chain] with Alternative[Chain] = Chain.catsDataInstancesForChain + def traverse: Traverse[Chain] & Alternative[Chain] = Chain.catsDataInstancesForChain override def filter[A](fa: Chain[A])(f: A => Boolean): Chain[A] = fa.filter(f) diff --git a/core/src/main/scala/cats/data/IndexedStateT.scala b/core/src/main/scala/cats/data/IndexedStateT.scala index 3d8d68cd34..8cfec758a6 100644 --- a/core/src/main/scala/cats/data/IndexedStateT.scala +++ b/core/src/main/scala/cats/data/IndexedStateT.scala @@ -279,7 +279,7 @@ sealed abstract private[data] class IndexedStateTInstances extends IndexedStateT implicit def catsDataAlternativeForIndexedStateT[F[_], S](implicit FM: Monad[F], FA: Alternative[F] - ): Alternative[IndexedStateT[F, S, S, *]] with Monad[IndexedStateT[F, S, S, *]] = + ): Alternative[IndexedStateT[F, S, S, *]] & Monad[IndexedStateT[F, S, S, *]] = new IndexedStateTAlternative[F, S] { implicit def F = FM; implicit def G = FA } implicit def catsDataDeferForIndexedStateT[F[_], SA, SB](implicit F: Defer[F]): Defer[IndexedStateT[F, SA, SB, *]] = diff --git a/core/src/main/scala/cats/data/Kleisli.scala b/core/src/main/scala/cats/data/Kleisli.scala index ce34adc147..fac3cb6949 100644 --- a/core/src/main/scala/cats/data/Kleisli.scala +++ b/core/src/main/scala/cats/data/Kleisli.scala @@ -389,7 +389,7 @@ sealed abstract private[data] class KleisliInstances0 extends KleisliInstances0_ implicit def catsDataCommutativeArrowForKleisli[F[_]](implicit M: CommutativeMonad[F] - ): CommutativeArrow[Kleisli[F, *, *]] with ArrowChoice[Kleisli[F, *, *]] = + ): CommutativeArrow[Kleisli[F, *, *]] & ArrowChoice[Kleisli[F, *, *]] = new KleisliCommutativeArrow[F] { def F: CommutativeMonad[F] = M } implicit def catsDataCommutativeMonadForKleisli[F[_], A](implicit diff --git a/core/src/main/scala/cats/data/Newtype.scala b/core/src/main/scala/cats/data/Newtype.scala index 4395fc4000..363d832569 100644 --- a/core/src/main/scala/cats/data/Newtype.scala +++ b/core/src/main/scala/cats/data/Newtype.scala @@ -31,5 +31,5 @@ package data private[data] trait Newtype { self => private[data] type Base private[data] trait Tag extends Any - type Type[A] <: Base with Tag + type Type[A] <: Base & Tag } diff --git a/core/src/main/scala/cats/data/Newtype2.scala b/core/src/main/scala/cats/data/Newtype2.scala index 78a458d0f4..404b80bbde 100644 --- a/core/src/main/scala/cats/data/Newtype2.scala +++ b/core/src/main/scala/cats/data/Newtype2.scala @@ -30,5 +30,5 @@ package data private[data] trait Newtype2 { self => private[data] type Base private[data] trait Tag extends Any - type Type[A, +B] <: Base with Tag + type Type[A, +B] <: Base & Tag } diff --git a/core/src/main/scala/cats/data/NonEmptyChain.scala b/core/src/main/scala/cats/data/NonEmptyChain.scala index 3ab876bc43..05abcb7dc0 100644 --- a/core/src/main/scala/cats/data/NonEmptyChain.scala +++ b/core/src/main/scala/cats/data/NonEmptyChain.scala @@ -42,7 +42,7 @@ object NonEmptyChainImpl extends NonEmptyChainInstances with ScalaVersionSpecifi private[data] type Base private[data] trait Tag extends Any /* aliased in data package as NonEmptyChain */ - type Type[+A] <: Base with Tag + type Type[+A] <: Base & Tag private[data] def create[A](s: Chain[A]): Type[A] = s.asInstanceOf[Type[A]] @@ -624,16 +624,16 @@ sealed abstract private[data] class NonEmptyChainInstances extends NonEmptyChain "maintained for the sake of binary compatibility only, use catsDataInstancesForNonEmptyChainBinCompat1 instead", "2.9.0" ) - def catsDataInstancesForNonEmptyChain: SemigroupK[NonEmptyChain] - with NonEmptyTraverse[NonEmptyChain] - with Bimonad[NonEmptyChain] - with Align[NonEmptyChain] = + def catsDataInstancesForNonEmptyChain + : SemigroupK[NonEmptyChain] & NonEmptyTraverse[NonEmptyChain] & Bimonad[NonEmptyChain] & Align[ + NonEmptyChain + ] = catsDataInstancesForNonEmptyChainBinCompat1 - implicit val catsDataInstancesForNonEmptyChainBinCompat1: Align[NonEmptyChain] - with Bimonad[NonEmptyChain] - with NonEmptyAlternative[NonEmptyChain] - with NonEmptyTraverse[NonEmptyChain] = + implicit val catsDataInstancesForNonEmptyChainBinCompat1 + : Align[NonEmptyChain] & Bimonad[NonEmptyChain] & NonEmptyAlternative[NonEmptyChain] & NonEmptyTraverse[ + NonEmptyChain + ] = new AbstractNonEmptyInstances[Chain, NonEmptyChain] with Align[NonEmptyChain] { def extract[A](fa: NonEmptyChain[A]): A = fa.head diff --git a/core/src/main/scala/cats/data/NonEmptyList.scala b/core/src/main/scala/cats/data/NonEmptyList.scala index b86ac76ec9..aae4265fdf 100644 --- a/core/src/main/scala/cats/data/NonEmptyList.scala +++ b/core/src/main/scala/cats/data/NonEmptyList.scala @@ -796,7 +796,7 @@ sealed abstract private[data] class NonEmptyListInstances extends NonEmptyListIn "2.9.0" ) def catsDataInstancesForNonEmptyList - : SemigroupK[NonEmptyList] with Bimonad[NonEmptyList] with NonEmptyTraverse[NonEmptyList] with Align[NonEmptyList] = + : SemigroupK[NonEmptyList] & Bimonad[NonEmptyList] & NonEmptyTraverse[NonEmptyList] & Align[NonEmptyList] = catsDataInstancesForNonEmptyListBinCompat1 /** @@ -805,10 +805,10 @@ sealed abstract private[data] class NonEmptyListInstances extends NonEmptyListIn * * Also see the discussion: PR #3541 and issue #3069. */ - implicit val catsDataInstancesForNonEmptyListBinCompat1: NonEmptyAlternative[NonEmptyList] - with Bimonad[NonEmptyList] - with NonEmptyTraverse[NonEmptyList] - with Align[NonEmptyList] = + implicit val catsDataInstancesForNonEmptyListBinCompat1 + : NonEmptyAlternative[NonEmptyList] & Bimonad[NonEmptyList] & NonEmptyTraverse[NonEmptyList] & Align[ + NonEmptyList + ] = new NonEmptyReducible[NonEmptyList, List] with NonEmptyAlternative[NonEmptyList] with Bimonad[NonEmptyList] diff --git a/core/src/main/scala/cats/data/NonEmptyMapImpl.scala b/core/src/main/scala/cats/data/NonEmptyMapImpl.scala index 9b8cebd01a..7b5bcb3d6f 100644 --- a/core/src/main/scala/cats/data/NonEmptyMapImpl.scala +++ b/core/src/main/scala/cats/data/NonEmptyMapImpl.scala @@ -296,7 +296,7 @@ sealed class NonEmptyMapOps[K, A](private[data] val value: NonEmptyMap[K, A]) { sealed abstract private[data] class NonEmptyMapInstances extends NonEmptyMapInstances0 { implicit def catsDataInstancesForNonEmptyMap[K] - : SemigroupK[NonEmptyMap[K, *]] with NonEmptyTraverse[NonEmptyMap[K, *]] with Align[NonEmptyMap[K, *]] = + : SemigroupK[NonEmptyMap[K, *]] & NonEmptyTraverse[NonEmptyMap[K, *]] & Align[NonEmptyMap[K, *]] = new SemigroupK[NonEmptyMap[K, *]] with NonEmptyTraverse[NonEmptyMap[K, *]] with Align[NonEmptyMap[K, *]] { override def map[A, B](fa: NonEmptyMap[K, A])(f: A => B): NonEmptyMap[K, B] = @@ -354,7 +354,7 @@ sealed abstract private[data] class NonEmptyMapInstances extends NonEmptyMapInst @deprecated("Use catsDataInstancesForNonEmptyMap override without Order", "2.2.0-M3") def catsDataInstancesForNonEmptyMap[K]( orderK: Order[K] - ): SemigroupK[NonEmptyMap[K, *]] with NonEmptyTraverse[NonEmptyMap[K, *]] with Align[NonEmptyMap[K, *]] = + ): SemigroupK[NonEmptyMap[K, *]] & NonEmptyTraverse[NonEmptyMap[K, *]] & Align[NonEmptyMap[K, *]] = catsDataInstancesForNonEmptyMap[K] implicit def catsDataHashForNonEmptyMap[K: Hash, A: Hash]: Hash[NonEmptyMap[K, A]] = diff --git a/core/src/main/scala/cats/data/NonEmptySeq.scala b/core/src/main/scala/cats/data/NonEmptySeq.scala index 65d76440fb..457a14b26e 100644 --- a/core/src/main/scala/cats/data/NonEmptySeq.scala +++ b/core/src/main/scala/cats/data/NonEmptySeq.scala @@ -403,7 +403,7 @@ sealed abstract private[data] class NonEmptySeqInstances { "2.9.0" ) def catsDataInstancesForNonEmptySeq - : SemigroupK[NonEmptySeq] with Bimonad[NonEmptySeq] with NonEmptyTraverse[NonEmptySeq] with Align[NonEmptySeq] = + : SemigroupK[NonEmptySeq] & Bimonad[NonEmptySeq] & NonEmptyTraverse[NonEmptySeq] & Align[NonEmptySeq] = catsDataInstancesForNonEmptySeqBinCompat1 /** @@ -412,10 +412,8 @@ sealed abstract private[data] class NonEmptySeqInstances { * * Also see the discussion: PR #3541 and issue #3069. */ - implicit val catsDataInstancesForNonEmptySeqBinCompat1: NonEmptyAlternative[NonEmptySeq] - with Bimonad[NonEmptySeq] - with NonEmptyTraverse[NonEmptySeq] - with Align[NonEmptySeq] = + implicit val catsDataInstancesForNonEmptySeqBinCompat1 + : NonEmptyAlternative[NonEmptySeq] & Bimonad[NonEmptySeq] & NonEmptyTraverse[NonEmptySeq] & Align[NonEmptySeq] = new NonEmptyReducible[NonEmptySeq, Seq] with NonEmptyAlternative[NonEmptySeq] with Bimonad[NonEmptySeq] diff --git a/core/src/main/scala/cats/data/NonEmptySet.scala b/core/src/main/scala/cats/data/NonEmptySet.scala index f9b7dd78a4..b0c2279aef 100644 --- a/core/src/main/scala/cats/data/NonEmptySet.scala +++ b/core/src/main/scala/cats/data/NonEmptySet.scala @@ -373,7 +373,7 @@ sealed class NonEmptySetOps[A](private[data] val value: NonEmptySet[A]) { } sealed abstract private[data] class NonEmptySetInstances extends NonEmptySetInstances0 { - implicit val catsDataInstancesForNonEmptySet: SemigroupK[NonEmptySet] with Reducible[NonEmptySet] = + implicit val catsDataInstancesForNonEmptySet: SemigroupK[NonEmptySet] & Reducible[NonEmptySet] = new SemigroupK[NonEmptySet] with Reducible[NonEmptySet] { def combineK[A](a: NonEmptySet[A], b: NonEmptySet[A]): NonEmptySet[A] = diff --git a/core/src/main/scala/cats/data/NonEmptyVector.scala b/core/src/main/scala/cats/data/NonEmptyVector.scala index 21f0d403e6..7dffe88ce3 100644 --- a/core/src/main/scala/cats/data/NonEmptyVector.scala +++ b/core/src/main/scala/cats/data/NonEmptyVector.scala @@ -393,10 +393,8 @@ sealed abstract private[data] class NonEmptyVectorInstances extends NonEmptyVect "maintained for the sake of binary compatibility only - use catsDataInstancesForNonEmptyChainBinCompat1 instead", "2.9.0" ) - def catsDataInstancesForNonEmptyVector: SemigroupK[NonEmptyVector] - with Bimonad[NonEmptyVector] - with NonEmptyTraverse[NonEmptyVector] - with Align[NonEmptyVector] = + def catsDataInstancesForNonEmptyVector + : SemigroupK[NonEmptyVector] & Bimonad[NonEmptyVector] & NonEmptyTraverse[NonEmptyVector] & Align[NonEmptyVector] = catsDataInstancesForNonEmptyVectorBinCompat1 /** @@ -405,10 +403,10 @@ sealed abstract private[data] class NonEmptyVectorInstances extends NonEmptyVect * * Also see the discussion: PR #3541 and issue #3069. */ - implicit val catsDataInstancesForNonEmptyVectorBinCompat1: NonEmptyAlternative[NonEmptyVector] - with Bimonad[NonEmptyVector] - with NonEmptyTraverse[NonEmptyVector] - with Align[NonEmptyVector] = + implicit val catsDataInstancesForNonEmptyVectorBinCompat1 + : NonEmptyAlternative[NonEmptyVector] & Bimonad[NonEmptyVector] & NonEmptyTraverse[NonEmptyVector] & Align[ + NonEmptyVector + ] = new NonEmptyReducible[NonEmptyVector, Vector] with NonEmptyAlternative[NonEmptyVector] with Bimonad[NonEmptyVector] diff --git a/core/src/main/scala/cats/instances/either.scala b/core/src/main/scala/cats/instances/either.scala index 586abc48c8..efe3a912b7 100644 --- a/core/src/main/scala/cats/instances/either.scala +++ b/core/src/main/scala/cats/instances/either.scala @@ -57,7 +57,7 @@ trait EitherInstances extends cats.kernel.instances.EitherInstances { } implicit def catsStdInstancesForEither[A] - : MonadError[Either[A, *], A] with Traverse[Either[A, *]] with Align[Either[A, *]] = + : MonadError[Either[A, *], A] & Traverse[Either[A, *]] & Align[Either[A, *]] = new MonadError[Either[A, *], A] with Traverse[Either[A, *]] with Align[Either[A, *]] { override def unit: Either[A, Unit] = Either.unit diff --git a/core/src/main/scala/cats/instances/function.scala b/core/src/main/scala/cats/instances/function.scala index 4233cd10a8..af1849307e 100644 --- a/core/src/main/scala/cats/instances/function.scala +++ b/core/src/main/scala/cats/instances/function.scala @@ -178,7 +178,7 @@ sealed private[instances] trait Function1Instances extends Function1Instances0 { } } - implicit val catsStdInstancesForFunction1: ArrowChoice[Function1] with CommutativeArrow[Function1] = + implicit val catsStdInstancesForFunction1: ArrowChoice[Function1] & CommutativeArrow[Function1] = new ArrowChoice[Function1] with CommutativeArrow[Function1] { def choose[A, B, C, D](f: A => C)(g: B => D): Either[A, B] => Either[C, D] = { case Left(a) => Left(f(a)) diff --git a/core/src/main/scala/cats/instances/future.scala b/core/src/main/scala/cats/instances/future.scala index 1faeca409e..cb38dc845c 100644 --- a/core/src/main/scala/cats/instances/future.scala +++ b/core/src/main/scala/cats/instances/future.scala @@ -38,7 +38,7 @@ trait FutureInstances extends FutureInstances1 { implicit def catsStdInstancesForFuture(implicit ec: ExecutionContext - ): MonadThrow[Future] with CoflatMap[Future] with Monad[Future] = + ): MonadThrow[Future] & CoflatMap[Future] & Monad[Future] = new FutureCoflatMap with MonadThrow[Future] with Monad[Future] with StackSafeMonad[Future] { override def pure[A](x: A): Future[A] = Future.successful(x) diff --git a/core/src/main/scala/cats/instances/list.scala b/core/src/main/scala/cats/instances/list.scala index a1306f159b..a8a48b5d9a 100644 --- a/core/src/main/scala/cats/instances/list.scala +++ b/core/src/main/scala/cats/instances/list.scala @@ -34,7 +34,7 @@ import scala.collection.mutable.ListBuffer trait ListInstances extends cats.kernel.instances.ListInstances { implicit val catsStdInstancesForList - : Traverse[List] with Alternative[List] with Monad[List] with CoflatMap[List] with Align[List] = + : Traverse[List] & Alternative[List] & Monad[List] & CoflatMap[List] & Align[List] = new Traverse[List] with Alternative[List] with Monad[List] with CoflatMap[List] with Align[List] { def empty[A]: List[A] = Nil diff --git a/core/src/main/scala/cats/instances/map.scala b/core/src/main/scala/cats/instances/map.scala index c469f88b5d..dfcc960bac 100644 --- a/core/src/main/scala/cats/instances/map.scala +++ b/core/src/main/scala/cats/instances/map.scala @@ -36,7 +36,7 @@ trait MapInstances extends cats.kernel.instances.MapInstances { .map { case (a, b) => showA.show(a) + " -> " + showB.show(b) } .mkString("Map(", ", ", ")") - implicit def catsStdInstancesForMap[K]: UnorderedTraverse[Map[K, *]] with FlatMap[Map[K, *]] with Align[Map[K, *]] = + implicit def catsStdInstancesForMap[K]: UnorderedTraverse[Map[K, *]] & FlatMap[Map[K, *]] & Align[Map[K, *]] = new UnorderedTraverse[Map[K, *]] with FlatMap[Map[K, *]] with Align[Map[K, *]] { def unorderedTraverse[G[_], A, B]( diff --git a/core/src/main/scala/cats/instances/option.scala b/core/src/main/scala/cats/instances/option.scala index 315b91f942..43abeec786 100644 --- a/core/src/main/scala/cats/instances/option.scala +++ b/core/src/main/scala/cats/instances/option.scala @@ -28,12 +28,9 @@ import cats.kernel.compat.scalaVersionSpecific._ trait OptionInstances extends cats.kernel.instances.OptionInstances { - implicit val catsStdInstancesForOption: Traverse[Option] - with MonadError[Option, Unit] - with Alternative[Option] - with CommutativeMonad[Option] - with CoflatMap[Option] - with Align[Option] = + implicit val catsStdInstancesForOption: Traverse[Option] & MonadError[Option, Unit] & Alternative[ + Option + ] & CommutativeMonad[Option] & CoflatMap[Option] & Align[Option] = new Traverse[Option] with MonadError[Option, Unit] with Alternative[Option] diff --git a/core/src/main/scala/cats/instances/partialFunction.scala b/core/src/main/scala/cats/instances/partialFunction.scala index 7ba7fbef49..2c0f9f0354 100644 --- a/core/src/main/scala/cats/instances/partialFunction.scala +++ b/core/src/main/scala/cats/instances/partialFunction.scala @@ -24,13 +24,13 @@ import cats.arrow.{ArrowChoice, CommutativeArrow} trait PartialFunctionInstances { - implicit def catsStdInstancesForPartialFunction: ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] = + implicit def catsStdInstancesForPartialFunction: ArrowChoice[PartialFunction] & CommutativeArrow[PartialFunction] = PartialFunctionInstances.instance } private object PartialFunctionInstances { - private val instance: ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] = + private val instance: ArrowChoice[PartialFunction] & CommutativeArrow[PartialFunction] = new ArrowChoice[PartialFunction] with CommutativeArrow[PartialFunction] { /** diff --git a/core/src/main/scala/cats/instances/queue.scala b/core/src/main/scala/cats/instances/queue.scala index bb10850423..44bbb60ddd 100644 --- a/core/src/main/scala/cats/instances/queue.scala +++ b/core/src/main/scala/cats/instances/queue.scala @@ -33,8 +33,7 @@ import scala.util.Try trait QueueInstances extends cats.kernel.instances.QueueInstances { - implicit val catsStdInstancesForQueue - : Traverse[Queue] with Alternative[Queue] with Monad[Queue] with CoflatMap[Queue] = + implicit val catsStdInstancesForQueue: Traverse[Queue] & Alternative[Queue] & Monad[Queue] & CoflatMap[Queue] = new Traverse[Queue] with Alternative[Queue] with Monad[Queue] with CoflatMap[Queue] { def empty[A]: Queue[A] = Queue.empty @@ -223,7 +222,7 @@ trait QueueInstances extends cats.kernel.instances.QueueInstances { @suppressUnusedImportWarningForScalaVersionSpecific private object QueueInstances { private val catsStdTraverseFilterForQueue: TraverseFilter[Queue] = new TraverseFilter[Queue] { - val traverse: Traverse[Queue] with Alternative[Queue] = cats.instances.queue.catsStdInstancesForQueue + val traverse: Traverse[Queue] & Alternative[Queue] = cats.instances.queue.catsStdInstancesForQueue override def mapFilter[A, B](fa: Queue[A])(f: (A) => Option[B]): Queue[B] = fa.collect(Function.unlift(f)) diff --git a/core/src/main/scala/cats/instances/seq.scala b/core/src/main/scala/cats/instances/seq.scala index 32272eb1f9..da8f9452eb 100644 --- a/core/src/main/scala/cats/instances/seq.scala +++ b/core/src/main/scala/cats/instances/seq.scala @@ -32,8 +32,7 @@ import scala.collection.immutable.Seq @suppressUnusedImportWarningForScalaVersionSpecific trait SeqInstances extends cats.kernel.instances.SeqInstances { - implicit val catsStdInstancesForSeq - : Traverse[Seq] with Monad[Seq] with Alternative[Seq] with CoflatMap[Seq] with Align[Seq] = + implicit val catsStdInstancesForSeq: Traverse[Seq] & Monad[Seq] & Alternative[Seq] & CoflatMap[Seq] & Align[Seq] = new Traverse[Seq] with Monad[Seq] with Alternative[Seq] with CoflatMap[Seq] with Align[Seq] { def empty[A]: Seq[A] = Seq.empty[A] diff --git a/core/src/main/scala/cats/instances/set.scala b/core/src/main/scala/cats/instances/set.scala index e3b9cee4b6..5597630bfa 100644 --- a/core/src/main/scala/cats/instances/set.scala +++ b/core/src/main/scala/cats/instances/set.scala @@ -26,7 +26,7 @@ import cats.kernel.CommutativeMonoid trait SetInstances extends cats.kernel.instances.SetInstances { - implicit val catsStdInstancesForSet: UnorderedTraverse[Set] with MonoidK[Set] = + implicit val catsStdInstancesForSet: UnorderedTraverse[Set] & MonoidK[Set] = new UnorderedTraverse[Set] with MonoidK[Set] { def unorderedTraverse[G[_]: CommutativeApplicative, A, B](sa: Set[A])(f: A => G[B]): G[Set[B]] = diff --git a/core/src/main/scala/cats/instances/sortedMap.scala b/core/src/main/scala/cats/instances/sortedMap.scala index 344176ff95..e219b03458 100644 --- a/core/src/main/scala/cats/instances/sortedMap.scala +++ b/core/src/main/scala/cats/instances/sortedMap.scala @@ -49,7 +49,7 @@ trait SortedMapInstances extends SortedMapInstances2 { catsStdShowForSortedMap(showA, showB) implicit def catsStdInstancesForSortedMap[K] - : Traverse[SortedMap[K, *]] with FlatMap[SortedMap[K, *]] with Align[SortedMap[K, *]] = + : Traverse[SortedMap[K, *]] & FlatMap[SortedMap[K, *]] & Align[SortedMap[K, *]] = new Traverse[SortedMap[K, *]] with FlatMap[SortedMap[K, *]] with Align[SortedMap[K, *]] { def traverse[G[_], A, B](fa: SortedMap[K, A])(f: A => G[B])(implicit G: Applicative[G]): G[SortedMap[K, B]] = { @@ -174,7 +174,7 @@ trait SortedMapInstances extends SortedMapInstances2 { @deprecated("Use catsStdInstancesForSortedMap override without Order", "2.2.0-M3") def catsStdInstancesForSortedMap[K]( orderK: Order[K] - ): Traverse[SortedMap[K, *]] with FlatMap[SortedMap[K, *]] with Align[SortedMap[K, *]] = + ): Traverse[SortedMap[K, *]] & FlatMap[SortedMap[K, *]] & Align[SortedMap[K, *]] = catsStdInstancesForSortedMap[K] } diff --git a/core/src/main/scala/cats/instances/sortedSet.scala b/core/src/main/scala/cats/instances/sortedSet.scala index 6fc5dec748..58df60337e 100644 --- a/core/src/main/scala/cats/instances/sortedSet.scala +++ b/core/src/main/scala/cats/instances/sortedSet.scala @@ -28,7 +28,7 @@ import scala.annotation.tailrec trait SortedSetInstances extends SortedSetInstances1 { - implicit val catsStdInstancesForSortedSet: Foldable[SortedSet] with SemigroupK[SortedSet] = + implicit val catsStdInstancesForSortedSet: Foldable[SortedSet] & SemigroupK[SortedSet] = new Foldable[SortedSet] with SemigroupK[SortedSet] { def combineK[A](x: SortedSet[A], y: SortedSet[A]): SortedSet[A] = x | y diff --git a/core/src/main/scala/cats/instances/tailrec.scala b/core/src/main/scala/cats/instances/tailrec.scala index 434e676aba..7fb4fbe684 100644 --- a/core/src/main/scala/cats/instances/tailrec.scala +++ b/core/src/main/scala/cats/instances/tailrec.scala @@ -25,12 +25,12 @@ package instances import scala.util.control.TailCalls.{done, tailcall, TailRec} trait TailRecInstances { - implicit def catsInstancesForTailRec: StackSafeMonad[TailRec] with Defer[TailRec] = + implicit def catsInstancesForTailRec: StackSafeMonad[TailRec] & Defer[TailRec] = TailRecInstances.catsInstancesForTailRec } private object TailRecInstances { - val catsInstancesForTailRec: StackSafeMonad[TailRec] with Defer[TailRec] = + val catsInstancesForTailRec: StackSafeMonad[TailRec] & Defer[TailRec] = new StackSafeMonad[TailRec] with Defer[TailRec] { def defer[A](fa: => TailRec[A]): TailRec[A] = tailcall(fa) diff --git a/core/src/main/scala/cats/instances/try.scala b/core/src/main/scala/cats/instances/try.scala index 49c39cd74a..8a69e752b1 100644 --- a/core/src/main/scala/cats/instances/try.scala +++ b/core/src/main/scala/cats/instances/try.scala @@ -30,7 +30,7 @@ import scala.annotation.tailrec trait TryInstances extends TryInstances1 { - implicit def catsStdInstancesForTry: MonadThrow[Try] with CoflatMap[Try] with Traverse[Try] with Monad[Try] = + implicit def catsStdInstancesForTry: MonadThrow[Try] & CoflatMap[Try] & Traverse[Try] & Monad[Try] = new TryCoflatMap with MonadThrow[Try] with Traverse[Try] with Monad[Try] { def pure[A](x: A): Try[A] = Success(x) diff --git a/core/src/main/scala/cats/instances/tuple.scala b/core/src/main/scala/cats/instances/tuple.scala index 5de8238ccb..eb47d7bae4 100644 --- a/core/src/main/scala/cats/instances/tuple.scala +++ b/core/src/main/scala/cats/instances/tuple.scala @@ -75,7 +75,7 @@ sealed private[instances] trait Tuple2Instances extends Tuple2Instances1 { } @deprecated("Use catsStdInstancesForTuple2 in cats.instances.NTupleMonadInstances", "2.4.0") - def catsStdInstancesForTuple2[X]: Traverse[(X, *)] with Comonad[(X, *)] with Reducible[(X, *)] = + def catsStdInstancesForTuple2[X]: Traverse[(X, *)] & Comonad[(X, *)] & Reducible[(X, *)] = new Traverse[(X, *)] with Comonad[(X, *)] with Reducible[(X, *)] { def traverse[G[_], A, B](fa: (X, A))(f: A => G[B])(implicit G: Applicative[G]): G[(X, B)] = G.map(f(fa._2))((fa._1, _)) diff --git a/core/src/main/scala/cats/instances/vector.scala b/core/src/main/scala/cats/instances/vector.scala index 06f93b4fef..d13b115790 100644 --- a/core/src/main/scala/cats/instances/vector.scala +++ b/core/src/main/scala/cats/instances/vector.scala @@ -31,7 +31,7 @@ import scala.collection.immutable.VectorBuilder trait VectorInstances extends cats.kernel.instances.VectorInstances { implicit val catsStdInstancesForVector - : Traverse[Vector] with Monad[Vector] with Alternative[Vector] with CoflatMap[Vector] with Align[Vector] = + : Traverse[Vector] & Monad[Vector] & Alternative[Vector] & CoflatMap[Vector] & Align[Vector] = new Traverse[Vector] with Monad[Vector] with Alternative[Vector] with CoflatMap[Vector] with Align[Vector] { def empty[A]: Vector[A] = Vector.empty[A] diff --git a/core/src/main/scala/cats/package.scala b/core/src/main/scala/cats/package.scala index 491926f25f..0a86548034 100644 --- a/core/src/main/scala/cats/package.scala +++ b/core/src/main/scala/cats/package.scala @@ -96,7 +96,7 @@ package object cats { type Endo[A] = A => A - val catsInstancesForId: Bimonad[Id] with CommutativeMonad[Id] with NonEmptyTraverse[Id] with Distributive[Id] = + val catsInstancesForId: Bimonad[Id] & CommutativeMonad[Id] & NonEmptyTraverse[Id] & Distributive[Id] = new Bimonad[Id] with CommutativeMonad[Id] with NonEmptyTraverse[Id] with Distributive[Id] { def pure[A](a: A): A = a def extract[A](a: A): A = a diff --git a/kernel-laws/shared/src/main/scala/cats/kernel/laws/EnumerableLaws.scala b/kernel-laws/shared/src/main/scala/cats/kernel/laws/EnumerableLaws.scala index c94def10df..e161339c6a 100644 --- a/kernel-laws/shared/src/main/scala/cats/kernel/laws/EnumerableLaws.scala +++ b/kernel-laws/shared/src/main/scala/cats/kernel/laws/EnumerableLaws.scala @@ -94,13 +94,13 @@ trait BoundedEnumerableLaws[A] extends PartialPreviousNextLaws[A] with PartialPreviousBoundedLaws[A] with PartialNextBoundedLaws[A] { - override def B: LowerBounded[A] with UpperBounded[A] + override def B: LowerBounded[A] & UpperBounded[A] } object BoundedEnumerableLaws { def apply[A](implicit ev: BoundedEnumerable[A]): BoundedEnumerableLaws[A] = new BoundedEnumerableLaws[A] { - val B: LowerBounded[A] with UpperBounded[A] = ev + val B: LowerBounded[A] & UpperBounded[A] = ev val E = ev.order val N: PartialNext[A] = ev val P: PartialPrevious[A] = ev diff --git a/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala b/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala index 208a0410dd..b108d06f45 100644 --- a/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala +++ b/kernel-laws/shared/src/test/scala/cats/kernel/laws/LawTests.scala @@ -464,7 +464,7 @@ class Tests extends TestsConfig with DisciplineSuite { .flatMap(x => Iterator.tabulate(nMax)(N).map((x, _))) .forall { case (x, y) => a.eqv(x, y) == b.eqv(x, y) } - implicit val monoidOrderN: Monoid[Order[N]] with Band[Order[N]] = Order.whenEqualMonoid[N] + implicit val monoidOrderN: Monoid[Order[N]] & Band[Order[N]] = Order.whenEqualMonoid[N] checkAll("Monoid[Order[N]]", MonoidTests[Order[N]].monoid) checkAll("Band[Order[N]]", BandTests[Order[N]].band) diff --git a/kernel/src/main/scala/cats/kernel/Comparison.scala b/kernel/src/main/scala/cats/kernel/Comparison.scala index c46887a248..abe333fcfb 100644 --- a/kernel/src/main/scala/cats/kernel/Comparison.scala +++ b/kernel/src/main/scala/cats/kernel/Comparison.scala @@ -47,7 +47,7 @@ object Comparison { else if (double == 0.0) SomeEq else SomeLt - implicit val catsKernelEqForComparison: Eq[Comparison] with Monoid[Comparison] = + implicit val catsKernelEqForComparison: Eq[Comparison] & Monoid[Comparison] = new Eq[Comparison] with Monoid[Comparison] { def eqv(x: Comparison, y: Comparison): Boolean = x == y def empty: Comparison = EqualTo diff --git a/kernel/src/main/scala/cats/kernel/Eq.scala b/kernel/src/main/scala/cats/kernel/Eq.scala index 585f43b87f..5f7dfe5a5c 100644 --- a/kernel/src/main/scala/cats/kernel/Eq.scala +++ b/kernel/src/main/scala/cats/kernel/Eq.scala @@ -149,43 +149,43 @@ object Eq } } - implicit def catsKernelInstancesForBitSet: PartialOrder[BitSet] with Hash[BitSet] = + implicit def catsKernelInstancesForBitSet: PartialOrder[BitSet] & Hash[BitSet] = cats.kernel.instances.bitSet.catsKernelStdOrderForBitSet implicit def catsKernelPartialOrderForSet[A]: PartialOrder[Set[A]] = cats.kernel.instances.set.catsKernelStdPartialOrderForSet[A] implicit def catsKernelOrderForEither[A: Order, B: Order]: Order[Either[A, B]] = cats.kernel.instances.either.catsStdOrderForEither[A, B] - implicit def catsKernelInstancesForUnit: Order[Unit] with Hash[Unit] = + implicit def catsKernelInstancesForUnit: Order[Unit] & Hash[Unit] = cats.kernel.instances.unit.catsKernelStdOrderForUnit - implicit def catsKernelInstancesForBoolean: Order[Boolean] with Hash[Boolean] = + implicit def catsKernelInstancesForBoolean: Order[Boolean] & Hash[Boolean] = cats.kernel.instances.boolean.catsKernelStdOrderForBoolean - implicit def catsKernelInstancesForByte: Order[Byte] with Hash[Byte] = + implicit def catsKernelInstancesForByte: Order[Byte] & Hash[Byte] = cats.kernel.instances.byte.catsKernelStdOrderForByte - implicit def catsKernelInstancesForShort: Order[Short] with Hash[Short] = + implicit def catsKernelInstancesForShort: Order[Short] & Hash[Short] = cats.kernel.instances.short.catsKernelStdOrderForShort - implicit def catsKernelInstancesForInt: Order[Int] with Hash[Int] = cats.kernel.instances.int.catsKernelStdOrderForInt - implicit def catsKernelInstancesForLong: Order[Long] with Hash[Long] = + implicit def catsKernelInstancesForInt: Order[Int] & Hash[Int] = cats.kernel.instances.int.catsKernelStdOrderForInt + implicit def catsKernelInstancesForLong: Order[Long] & Hash[Long] = cats.kernel.instances.long.catsKernelStdOrderForLong - implicit def catsKernelInstancesForBigInt: Order[BigInt] with Hash[BigInt] = + implicit def catsKernelInstancesForBigInt: Order[BigInt] & Hash[BigInt] = cats.kernel.instances.bigInt.catsKernelStdOrderForBigInt - implicit def catsKernelInstancesForBigDecimal: Order[BigDecimal] with Hash[BigDecimal] = + implicit def catsKernelInstancesForBigDecimal: Order[BigDecimal] & Hash[BigDecimal] = cats.kernel.instances.bigDecimal.catsKernelStdOrderForBigDecimal - implicit def catsKernelInstancesForDuration: Order[Duration] with Hash[Duration] = + implicit def catsKernelInstancesForDuration: Order[Duration] & Hash[Duration] = cats.kernel.instances.duration.catsKernelStdOrderForDuration - implicit def catsKernelInstancesForFiniteDuration: Order[FiniteDuration] with Hash[FiniteDuration] = + implicit def catsKernelInstancesForFiniteDuration: Order[FiniteDuration] & Hash[FiniteDuration] = cats.kernel.instances.all.catsKernelStdOrderForFiniteDuration - implicit def catsKernelInstancesForChar: Order[Char] with Hash[Char] = + implicit def catsKernelInstancesForChar: Order[Char] & Hash[Char] = cats.kernel.instances.char.catsKernelStdOrderForChar - implicit def catsKernelInstancesForSymbol: Order[Symbol] with Hash[Symbol] = + implicit def catsKernelInstancesForSymbol: Order[Symbol] & Hash[Symbol] = cats.kernel.instances.symbol.catsKernelStdOrderForSymbol - implicit def catsKernelInstancesForString: Order[String] with Hash[String] = + implicit def catsKernelInstancesForString: Order[String] & Hash[String] = cats.kernel.instances.string.catsKernelStdOrderForString - implicit def catsKernelInstancesForUUID: Order[UUID] with Hash[UUID] = + implicit def catsKernelInstancesForUUID: Order[UUID] & Hash[UUID] = cats.kernel.instances.uuid.catsKernelStdOrderForUUID - implicit def catsKernelInstancesForDouble: Order[Double] with Hash[Double] = + implicit def catsKernelInstancesForDouble: Order[Double] & Hash[Double] = cats.kernel.instances.double.catsKernelStdOrderForDouble - implicit def catsKernelInstancesForFloat: Order[Float] with Hash[Float] = + implicit def catsKernelInstancesForFloat: Order[Float] & Hash[Float] = cats.kernel.instances.float.catsKernelStdOrderForFloat implicit def catsKernelOrderForOption[A: Order]: Order[Option[A]] = diff --git a/kernel/src/main/scala/cats/kernel/Order.scala b/kernel/src/main/scala/cats/kernel/Order.scala index a9a6ffb3c6..ab0e80dc46 100644 --- a/kernel/src/main/scala/cats/kernel/Order.scala +++ b/kernel/src/main/scala/cats/kernel/Order.scala @@ -220,7 +220,7 @@ object Order extends OrderFunctions[Order] with OrderToOrderingConversion { * * @see [[Order.whenEqual]] */ - def whenEqualMonoid[A]: Monoid[Order[A]] with Band[Order[A]] = + def whenEqualMonoid[A]: Monoid[Order[A]] & Band[Order[A]] = new Monoid[Order[A]] with Band[Order[A]] { val empty: Order[A] = allEqual[A] def combine(x: Order[A], y: Order[A]): Order[A] = Order.whenEqual(x, y) diff --git a/kernel/src/main/scala/cats/kernel/Semigroup.scala b/kernel/src/main/scala/cats/kernel/Semigroup.scala index e861f481fe..19917e4792 100644 --- a/kernel/src/main/scala/cats/kernel/Semigroup.scala +++ b/kernel/src/main/scala/cats/kernel/Semigroup.scala @@ -180,7 +180,7 @@ object Semigroup implicit def catsKernelBoundedSemilatticeForBitSet: BoundedSemilattice[BitSet] = cats.kernel.instances.bitSet.catsKernelStdSemilatticeForBitSet - implicit def catsKernelInstancesForUnit: BoundedSemilattice[Unit] with CommutativeGroup[Unit] = + implicit def catsKernelInstancesForUnit: BoundedSemilattice[Unit] & CommutativeGroup[Unit] = cats.kernel.instances.unit.catsKernelStdAlgebraForUnit implicit def catsKernelCommutativeGroupForByte: CommutativeGroup[Byte] = cats.kernel.instances.byte.catsKernelStdGroupForByte diff --git a/kernel/src/main/scala/cats/kernel/instances/BigDecimalInstances.scala b/kernel/src/main/scala/cats/kernel/instances/BigDecimalInstances.scala index 3760178ee4..2e430423b1 100644 --- a/kernel/src/main/scala/cats/kernel/instances/BigDecimalInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/BigDecimalInstances.scala @@ -23,7 +23,7 @@ package cats.kernel package instances trait BigDecimalInstances { - implicit val catsKernelStdOrderForBigDecimal: Order[BigDecimal] with Hash[BigDecimal] = + implicit val catsKernelStdOrderForBigDecimal: Order[BigDecimal] & Hash[BigDecimal] = new BigDecimalOrder implicit val catsKernelStdGroupForBigDecimal: CommutativeGroup[BigDecimal] = new BigDecimalGroup diff --git a/kernel/src/main/scala/cats/kernel/instances/BigIntInstances.scala b/kernel/src/main/scala/cats/kernel/instances/BigIntInstances.scala index 83a7360959..c0d55700b5 100644 --- a/kernel/src/main/scala/cats/kernel/instances/BigIntInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/BigIntInstances.scala @@ -23,7 +23,7 @@ package cats.kernel package instances trait BigIntInstances { - implicit val catsKernelStdOrderForBigInt: Order[BigInt] with Hash[BigInt] with UnboundedEnumerable[BigInt] = + implicit val catsKernelStdOrderForBigInt: Order[BigInt] & Hash[BigInt] & UnboundedEnumerable[BigInt] = new BigIntOrder implicit val catsKernelStdGroupForBigInt: CommutativeGroup[BigInt] = new BigIntGroup diff --git a/kernel/src/main/scala/cats/kernel/instances/BitSetInstances.scala b/kernel/src/main/scala/cats/kernel/instances/BitSetInstances.scala index 0efe50bd12..5ac0ea8a04 100644 --- a/kernel/src/main/scala/cats/kernel/instances/BitSetInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/BitSetInstances.scala @@ -25,7 +25,7 @@ package instances import scala.collection.immutable.BitSet trait BitSetInstances { - implicit val catsKernelStdOrderForBitSet: PartialOrder[BitSet] with Hash[BitSet] = + implicit val catsKernelStdOrderForBitSet: PartialOrder[BitSet] & Hash[BitSet] = new BitSetPartialOrder implicit val catsKernelStdSemilatticeForBitSet: BoundedSemilattice[BitSet] = diff --git a/kernel/src/main/scala/cats/kernel/instances/BooleanInstances.scala b/kernel/src/main/scala/cats/kernel/instances/BooleanInstances.scala index ad818d478d..073567990d 100644 --- a/kernel/src/main/scala/cats/kernel/instances/BooleanInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/BooleanInstances.scala @@ -23,7 +23,7 @@ package cats.kernel package instances trait BooleanInstances { - implicit val catsKernelStdOrderForBoolean: Order[Boolean] with Hash[Boolean] with BoundedEnumerable[Boolean] = + implicit val catsKernelStdOrderForBoolean: Order[Boolean] & Hash[Boolean] & BoundedEnumerable[Boolean] = new BooleanOrder } diff --git a/kernel/src/main/scala/cats/kernel/instances/ByteInstances.scala b/kernel/src/main/scala/cats/kernel/instances/ByteInstances.scala index 8d767997ef..1d1a146ede 100644 --- a/kernel/src/main/scala/cats/kernel/instances/ByteInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/ByteInstances.scala @@ -23,7 +23,7 @@ package cats.kernel package instances trait ByteInstances { - implicit val catsKernelStdOrderForByte: Order[Byte] with Hash[Byte] with BoundedEnumerable[Byte] = + implicit val catsKernelStdOrderForByte: Order[Byte] & Hash[Byte] & BoundedEnumerable[Byte] = new ByteOrder implicit val catsKernelStdGroupForByte: CommutativeGroup[Byte] = new ByteGroup } diff --git a/kernel/src/main/scala/cats/kernel/instances/CharInstances.scala b/kernel/src/main/scala/cats/kernel/instances/CharInstances.scala index 2ff7b77f08..a6ce953410 100644 --- a/kernel/src/main/scala/cats/kernel/instances/CharInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/CharInstances.scala @@ -23,7 +23,7 @@ package cats.kernel package instances trait CharInstances { - implicit val catsKernelStdOrderForChar: CharOrder with Hash[Char] with BoundedEnumerable[Char] = new CharOrder + implicit val catsKernelStdOrderForChar: CharOrder & Hash[Char] & BoundedEnumerable[Char] = new CharOrder } trait CharEnumerable extends BoundedEnumerable[Char] { diff --git a/kernel/src/main/scala/cats/kernel/instances/DeadlineInstances.scala b/kernel/src/main/scala/cats/kernel/instances/DeadlineInstances.scala index 291ce3bc6e..f36e66462c 100644 --- a/kernel/src/main/scala/cats/kernel/instances/DeadlineInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/DeadlineInstances.scala @@ -27,7 +27,7 @@ import scala.concurrent.duration.{Deadline, FiniteDuration} trait DeadlineInstances { implicit val catsKernelStdOrderForDeadline - : Order[Deadline] with Hash[Deadline] with LowerBounded[Deadline] with UpperBounded[Deadline] = new DeadlineOrder + : Order[Deadline] & Hash[Deadline] & LowerBounded[Deadline] & UpperBounded[Deadline] = new DeadlineOrder } trait DeadlineBounded extends LowerBounded[Deadline] with UpperBounded[Deadline] { diff --git a/kernel/src/main/scala/cats/kernel/instances/DoubleInstances.scala b/kernel/src/main/scala/cats/kernel/instances/DoubleInstances.scala index a90aa04d4e..240a69b54e 100644 --- a/kernel/src/main/scala/cats/kernel/instances/DoubleInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/DoubleInstances.scala @@ -23,7 +23,7 @@ package cats.kernel package instances trait DoubleInstances { - implicit val catsKernelStdOrderForDouble: Order[Double] with Hash[Double] = new DoubleOrder + implicit val catsKernelStdOrderForDouble: Order[Double] & Hash[Double] = new DoubleOrder implicit val catsKernelStdGroupForDouble: CommutativeGroup[Double] = new DoubleGroup } diff --git a/kernel/src/main/scala/cats/kernel/instances/DurationInstances.scala b/kernel/src/main/scala/cats/kernel/instances/DurationInstances.scala index 0eb8fd8be2..22314757d7 100644 --- a/kernel/src/main/scala/cats/kernel/instances/DurationInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/DurationInstances.scala @@ -26,7 +26,7 @@ import scala.concurrent.duration.Duration trait DurationInstances { implicit val catsKernelStdOrderForDuration - : Order[Duration] with Hash[Duration] with LowerBounded[Duration] with UpperBounded[Duration] = new DurationOrder + : Order[Duration] & Hash[Duration] & LowerBounded[Duration] & UpperBounded[Duration] = new DurationOrder implicit val catsKernelStdGroupForDuration: CommutativeGroup[Duration] = new DurationGroup } diff --git a/kernel/src/main/scala/cats/kernel/instances/FiniteDurationInstances.scala b/kernel/src/main/scala/cats/kernel/instances/FiniteDurationInstances.scala index 41495d364c..91ac2757a1 100644 --- a/kernel/src/main/scala/cats/kernel/instances/FiniteDurationInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/FiniteDurationInstances.scala @@ -27,10 +27,9 @@ import java.util.concurrent.TimeUnit import scala.concurrent.duration.{Duration, FiniteDuration} trait FiniteDurationInstances { - implicit val catsKernelStdOrderForFiniteDuration: Order[FiniteDuration] - with Hash[FiniteDuration] - with LowerBounded[FiniteDuration] - with UpperBounded[FiniteDuration] = new FiniteDurationOrder + implicit val catsKernelStdOrderForFiniteDuration + : Order[FiniteDuration] & Hash[FiniteDuration] & LowerBounded[FiniteDuration] & UpperBounded[FiniteDuration] = + new FiniteDurationOrder implicit val catsKernelStdGroupForFiniteDuration: CommutativeGroup[FiniteDuration] = new FiniteDurationGroup } diff --git a/kernel/src/main/scala/cats/kernel/instances/FloatInstances.scala b/kernel/src/main/scala/cats/kernel/instances/FloatInstances.scala index 989d3a82a7..42b0838694 100644 --- a/kernel/src/main/scala/cats/kernel/instances/FloatInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/FloatInstances.scala @@ -23,7 +23,7 @@ package cats.kernel package instances trait FloatInstances { - implicit val catsKernelStdOrderForFloat: Order[Float] with Hash[Float] = new FloatOrder + implicit val catsKernelStdOrderForFloat: Order[Float] & Hash[Float] = new FloatOrder implicit val catsKernelStdGroupForFloat: CommutativeGroup[Float] = new FloatGroup } diff --git a/kernel/src/main/scala/cats/kernel/instances/IntInstances.scala b/kernel/src/main/scala/cats/kernel/instances/IntInstances.scala index a0c3b5366e..9980bca8bb 100644 --- a/kernel/src/main/scala/cats/kernel/instances/IntInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/IntInstances.scala @@ -23,7 +23,7 @@ package cats.kernel package instances trait IntInstances { - implicit val catsKernelStdOrderForInt: Order[Int] with Hash[Int] with BoundedEnumerable[Int] = + implicit val catsKernelStdOrderForInt: Order[Int] & Hash[Int] & BoundedEnumerable[Int] = new IntOrder implicit val catsKernelStdGroupForInt: CommutativeGroup[Int] = new IntGroup } diff --git a/kernel/src/main/scala/cats/kernel/instances/LongInstances.scala b/kernel/src/main/scala/cats/kernel/instances/LongInstances.scala index 8be97210c8..76882f3ed2 100644 --- a/kernel/src/main/scala/cats/kernel/instances/LongInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/LongInstances.scala @@ -23,7 +23,7 @@ package cats.kernel package instances trait LongInstances { - implicit val catsKernelStdOrderForLong: Order[Long] with Hash[Long] with BoundedEnumerable[Long] = + implicit val catsKernelStdOrderForLong: Order[Long] & Hash[Long] & BoundedEnumerable[Long] = new LongOrder implicit val catsKernelStdGroupForLong: CommutativeGroup[Long] = new LongGroup } diff --git a/kernel/src/main/scala/cats/kernel/instances/ShortInstances.scala b/kernel/src/main/scala/cats/kernel/instances/ShortInstances.scala index 070f5bc203..0775ae2c69 100644 --- a/kernel/src/main/scala/cats/kernel/instances/ShortInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/ShortInstances.scala @@ -23,7 +23,7 @@ package cats.kernel package instances trait ShortInstances { - implicit val catsKernelStdOrderForShort: Order[Short] with Hash[Short] with BoundedEnumerable[Short] = new ShortOrder + implicit val catsKernelStdOrderForShort: Order[Short] & Hash[Short] & BoundedEnumerable[Short] = new ShortOrder implicit val catsKernelStdGroupForShort: CommutativeGroup[Short] = new ShortGroup } diff --git a/kernel/src/main/scala/cats/kernel/instances/StringInstances.scala b/kernel/src/main/scala/cats/kernel/instances/StringInstances.scala index d4ad88128b..f8554a2ea4 100644 --- a/kernel/src/main/scala/cats/kernel/instances/StringInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/StringInstances.scala @@ -24,7 +24,7 @@ package instances import compat.scalaVersionSpecific._ @suppressUnusedImportWarningForScalaVersionSpecific trait StringInstances { - implicit val catsKernelStdOrderForString: Order[String] with Hash[String] with LowerBounded[String] = new StringOrder + implicit val catsKernelStdOrderForString: Order[String] & Hash[String] & LowerBounded[String] = new StringOrder implicit val catsKernelStdMonoidForString: Monoid[String] = new StringMonoid } diff --git a/kernel/src/main/scala/cats/kernel/instances/SymbolInstances.scala b/kernel/src/main/scala/cats/kernel/instances/SymbolInstances.scala index 3e5b242e44..9d5ffba876 100644 --- a/kernel/src/main/scala/cats/kernel/instances/SymbolInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/SymbolInstances.scala @@ -23,7 +23,7 @@ package cats.kernel package instances trait SymbolInstances { - implicit val catsKernelStdOrderForSymbol: Order[Symbol] with Hash[Symbol] with LowerBounded[Symbol] = new SymbolOrder + implicit val catsKernelStdOrderForSymbol: Order[Symbol] & Hash[Symbol] & LowerBounded[Symbol] = new SymbolOrder } trait SymbolLowerBounded extends LowerBounded[Symbol] { diff --git a/kernel/src/main/scala/cats/kernel/instances/UUIDInstances.scala b/kernel/src/main/scala/cats/kernel/instances/UUIDInstances.scala index ab358dac35..62fbaec5f5 100644 --- a/kernel/src/main/scala/cats/kernel/instances/UUIDInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/UUIDInstances.scala @@ -25,7 +25,7 @@ package instances import java.util.UUID trait UUIDInstances { - implicit val catsKernelStdOrderForUUID: Order[UUID] with Hash[UUID] with LowerBounded[UUID] with UpperBounded[UUID] = + implicit val catsKernelStdOrderForUUID: Order[UUID] & Hash[UUID] & LowerBounded[UUID] & UpperBounded[UUID] = new Order[UUID] with Hash[UUID] with UUIDBounded { self => def compare(x: UUID, y: UUID): Int = x.compareTo(y) def hash(x: UUID): Int = x.hashCode() diff --git a/kernel/src/main/scala/cats/kernel/instances/UnitInstances.scala b/kernel/src/main/scala/cats/kernel/instances/UnitInstances.scala index b7b28974a6..bd6b3a7ad9 100644 --- a/kernel/src/main/scala/cats/kernel/instances/UnitInstances.scala +++ b/kernel/src/main/scala/cats/kernel/instances/UnitInstances.scala @@ -25,10 +25,10 @@ import compat.scalaVersionSpecific._ @suppressUnusedImportWarningForScalaVersionSpecific trait UnitInstances { - implicit val catsKernelStdOrderForUnit: Order[Unit] with Hash[Unit] with BoundedEnumerable[Unit] = + implicit val catsKernelStdOrderForUnit: Order[Unit] & Hash[Unit] & BoundedEnumerable[Unit] = new UnitOrder - implicit val catsKernelStdAlgebraForUnit: BoundedSemilattice[Unit] with CommutativeGroup[Unit] = + implicit val catsKernelStdAlgebraForUnit: BoundedSemilattice[Unit] & CommutativeGroup[Unit] = new UnitAlgebra } diff --git a/laws/src/main/scala/cats/laws/discipline/MiniInt.scala b/laws/src/main/scala/cats/laws/discipline/MiniInt.scala index af67cfa642..ffd877221e 100644 --- a/laws/src/main/scala/cats/laws/discipline/MiniInt.scala +++ b/laws/src/main/scala/cats/laws/discipline/MiniInt.scala @@ -72,7 +72,7 @@ object MiniInt { val allValues: List[MiniInt] = (minIntValue to maxIntValue).map(unsafeFromInt).toList - implicit val catsLawsEqInstancesForMiniInt: Order[MiniInt] with Hash[MiniInt] = + implicit val catsLawsEqInstancesForMiniInt: Order[MiniInt] & Hash[MiniInt] = new Order[MiniInt] with Hash[MiniInt] { def hash(x: MiniInt): Int = Hash[Int].hash(x.intBits) diff --git a/tests/shared/src/test/scala/cats/tests/AlgebraInvariantSuite.scala b/tests/shared/src/test/scala/cats/tests/AlgebraInvariantSuite.scala index ac6753adef..fa8fabace7 100644 --- a/tests/shared/src/test/scala/cats/tests/AlgebraInvariantSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/AlgebraInvariantSuite.scala @@ -174,8 +174,7 @@ class AlgebraInvariantSuite extends CatsSuite with ScalaVersionSpecificAlgebraIn implicit private val arbCommutativeGroupInt: Arbitrary[CommutativeGroup[Int]] = Arbitrary(genCommutativeGroupInt) - protected val integralForMiniInt: Numeric[MiniInt] with Integral[MiniInt] = new MiniIntNumeric - with Integral[MiniInt] { + protected val integralForMiniInt: Numeric[MiniInt] & Integral[MiniInt] = new MiniIntNumeric with Integral[MiniInt] { def quot(x: MiniInt, y: MiniInt): MiniInt = MiniInt.unsafeFromInt(x.toInt / y.toInt) def rem(x: MiniInt, y: MiniInt): MiniInt = MiniInt.unsafeFromInt(x.toInt % y.toInt) } From 4bb630a4fa413dd3f3ef44189fda3c3b73d8f689 Mon Sep 17 00:00:00 2001 From: aluscent Date: Tue, 3 Dec 2024 17:17:07 +0330 Subject: [PATCH 084/123] Made ExtractOps class a value class Wrote tests for alleycats module --- .../main/scala/alleycats/syntax/extract.scala | 8 ++- .../test/scala/alleycats/SyntaxSuite.scala | 67 +++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 alleycats-core/src/test/scala/alleycats/SyntaxSuite.scala diff --git a/alleycats-core/src/main/scala/alleycats/syntax/extract.scala b/alleycats-core/src/main/scala/alleycats/syntax/extract.scala index 3ba0697975..78d5272599 100644 --- a/alleycats-core/src/main/scala/alleycats/syntax/extract.scala +++ b/alleycats-core/src/main/scala/alleycats/syntax/extract.scala @@ -27,7 +27,9 @@ import alleycats.Extract object extract extends ExtractSyntax trait ExtractSyntax { - implicit final class ExtractOps[F[_], A](private val fa: F[A]) extends AnyVal { - def extract(implicit ev: Extract[F]): A = ev.extract(fa) - } + implicit final def catsSyntaxExtract[F[_], A](fa: F[A]): ExtractOps[F, A] = new ExtractOps[F, A](fa) +} + +final private[alleycats] class ExtractOps[F[_], A](private val fa: F[A]) extends AnyVal { + def extract(implicit F: Extract[F]): A = F.extract(fa) } diff --git a/alleycats-core/src/test/scala/alleycats/SyntaxSuite.scala b/alleycats-core/src/test/scala/alleycats/SyntaxSuite.scala new file mode 100644 index 0000000000..40e1ba713d --- /dev/null +++ b/alleycats-core/src/test/scala/alleycats/SyntaxSuite.scala @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015 Typelevel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package alleycats + +import cats.{Eq, Foldable} +import alleycats.syntax.all.{EmptyOps, ExtraFoldableOps, catsSyntaxExtract} + +/** + * Test that our syntax implicits are working. + * + * Each method should correspond to one type class worth of syntax. + * Ideally, we should be testing every operator or method that we + * expect to add to generic parameters. This file is a safeguard + * against accidentally breaking (or removing) syntax which was + * otherwise untested. + * + * The strategy here is to create "mock" values of particular types, + * and then ensure that the syntax we want is available. We never plan + * to run any of these methods, so we don't need real values. All + * values in the methods should be generic -- we rely on parametricity + * to guarantee that the syntax will be available for any type with + * the proper type class instance(s). + * + * None of these tests should ever run, or do any runtime checks. + */ +object SyntaxSuite { + + // pretend we have a value of type A + def mock[A]: A = ??? + + def testEmpty[A: Empty]: Unit = { + val x = mock[A] + implicit val y: Eq[A] = mock[Eq[A]] + val a0: Boolean = x.isEmpty + val a1: Boolean = x.nonEmpty + } + + def testFoldable[F[_]: Foldable, A]: Unit = { + val x = mock[F[A]] + val y = mock[A => Unit] + x.foreach(y) + } + + def testExtract[F[_]: Extract, A]: Unit = { + val x = mock[F[A]] + val y = x.extract + } +} From 843182c127bff0b892c5d74a7a95df9a121f71b2 Mon Sep 17 00:00:00 2001 From: aluscent Date: Tue, 3 Dec 2024 17:31:05 +0330 Subject: [PATCH 085/123] Applied scalafmt on file --- alleycats-core/src/test/scala/alleycats/SyntaxSuite.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alleycats-core/src/test/scala/alleycats/SyntaxSuite.scala b/alleycats-core/src/test/scala/alleycats/SyntaxSuite.scala index 40e1ba713d..71a8867f14 100644 --- a/alleycats-core/src/test/scala/alleycats/SyntaxSuite.scala +++ b/alleycats-core/src/test/scala/alleycats/SyntaxSuite.scala @@ -22,7 +22,7 @@ package alleycats import cats.{Eq, Foldable} -import alleycats.syntax.all.{EmptyOps, ExtraFoldableOps, catsSyntaxExtract} +import alleycats.syntax.all.{catsSyntaxExtract, EmptyOps, ExtraFoldableOps} /** * Test that our syntax implicits are working. From 41d24a863d32d89ff8fafb9fc6b3ddd680ab5e74 Mon Sep 17 00:00:00 2001 From: Sergey Torgashov Date: Tue, 3 Dec 2024 21:19:28 -0800 Subject: [PATCH 086/123] move val to the companion object --- .../src/main/scala/alleycats/std/set.scala | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/alleycats-core/src/main/scala/alleycats/std/set.scala b/alleycats-core/src/main/scala/alleycats/std/set.scala index bff022b424..d5ef1b7f7b 100644 --- a/alleycats-core/src/main/scala/alleycats/std/set.scala +++ b/alleycats-core/src/main/scala/alleycats/std/set.scala @@ -31,6 +31,8 @@ object set extends SetInstances @suppressUnusedImportWarningForScalaVersionSpecific trait SetInstances { + import SetInstances._ + // Monad advertises parametricity, but Set relies on using // universal hash codes and equality, which hurts our ability to // rely on free theorems. @@ -55,7 +57,20 @@ trait SetInstances { // If we accept Monad for Set, we can also have Alternative, as // Alternative only requires MonoidK (already accepted by cats-core) and // the Applicative that comes from Monad. - implicit val alleycatsStdInstancesForSet + implicit def alleycatsStdInstancesForSet + : Monad[Set] with Alternative[Set] with Traverse[Set] with TraverseFilter[Set] = + alleycatsStdInstancesForSet_ + + @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") + val alleyCatsSetTraverse: Traverse[Set] = alleycatsStdInstancesForSet_ + @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") + val alleyCatsStdSetMonad: Monad[Set] with Alternative[Set] = alleycatsStdInstancesForSet_ + @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") + val alleyCatsSetTraverseFilter: TraverseFilter[Set] = alleycatsStdInstancesForSet_ +} + +private[alleycats] object SetInstances { + private val alleycatsStdInstancesForSet_ : Monad[Set] with Alternative[Set] with Traverse[Set] with TraverseFilter[Set] = new Monad[Set] with Alternative[Set] with Traverse[Set] with TraverseFilter[Set] { val traverse: Traverse[Set] = this @@ -77,7 +92,7 @@ trait SetInstances { if (fa.isEmpty) Eval.now(Set.empty[Z]) // no need to evaluate fb else fb.map(fb => map2(fa, fb)(f)) - def tailRecM[A, B](a: A)(f: (A) => Set[Either[A, B]]): Set[B] = { + def tailRecM[A, B](a: A)(f: A => Set[Either[A, B]]): Set[B] = { val bldr = Set.newBuilder[B] @tailrec def go(set: Set[Either[A, B]]): Unit = { @@ -174,11 +189,4 @@ trait SetInstances { override def collectFirstSome[A, B](fa: Set[A])(f: A => Option[B]): Option[B] = fa.collectFirst(Function.unlift(f)) } - - @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") - val alleyCatsSetTraverse: Traverse[Set] = alleycatsStdInstancesForSet - @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") - val alleyCatsStdSetMonad: Monad[Set] with Alternative[Set] = alleycatsStdInstancesForSet - @deprecated("Use alleycatsStdInstancesForSet", "2.13.0") - val alleyCatsSetTraverseFilter: TraverseFilter[Set] = alleycatsStdInstancesForSet } From 336144c0ef8b38b7d3a56ed26714db6a5caf4ef5 Mon Sep 17 00:00:00 2001 From: Laurence Warne Date: Wed, 4 Dec 2024 18:09:27 +0000 Subject: [PATCH 087/123] Add note about def --- alleycats-core/src/main/scala/alleycats/std/set.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/alleycats-core/src/main/scala/alleycats/std/set.scala b/alleycats-core/src/main/scala/alleycats/std/set.scala index d5ef1b7f7b..f3bf304734 100644 --- a/alleycats-core/src/main/scala/alleycats/std/set.scala +++ b/alleycats-core/src/main/scala/alleycats/std/set.scala @@ -33,6 +33,9 @@ object set extends SetInstances trait SetInstances { import SetInstances._ + // We use a def instead of val here as a workaround to the MiMa + // 'ReversedMissingMethodProblem' error. + implicit def alleycatsStdInstancesForSet // Monad advertises parametricity, but Set relies on using // universal hash codes and equality, which hurts our ability to // rely on free theorems. @@ -57,7 +60,6 @@ trait SetInstances { // If we accept Monad for Set, we can also have Alternative, as // Alternative only requires MonoidK (already accepted by cats-core) and // the Applicative that comes from Monad. - implicit def alleycatsStdInstancesForSet : Monad[Set] with Alternative[Set] with Traverse[Set] with TraverseFilter[Set] = alleycatsStdInstancesForSet_ From 1d8fa144511d31c1debc538de8a8b2f01ff1de71 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Fri, 13 Dec 2024 00:20:00 +0000 Subject: [PATCH 088/123] Update sbt-doctest to 0.11.1 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index efdd41b5c7..02e9d60e0b 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,7 +2,7 @@ val sbtTypelevelVersion = "0.7.4" addSbtPlugin("org.typelevel" % "sbt-typelevel" % sbtTypelevelVersion) addSbtPlugin("org.typelevel" % "sbt-typelevel-site" % sbtTypelevelVersion) addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") -addSbtPlugin("io.github.sbt-doctest" % "sbt-doctest" % "0.11.0") +addSbtPlugin("io.github.sbt-doctest" % "sbt-doctest" % "0.11.1") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.6") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.13.1") From 3b066e699ff2c58d9c7996f6215ecec9d8e8e2fe Mon Sep 17 00:00:00 2001 From: satorg Date: Sun, 3 Nov 2024 21:03:27 -0800 Subject: [PATCH 089/123] add `sequenceVoid` and `traverseVoid` to `Foldable` --- core/src/main/scala/cats/Foldable.scala | 43 +++++++++++++++---- .../src/main/scala/cats/syntax/foldable.scala | 7 ++- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index c7ecdd326a..e1fccb4a72 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -578,9 +578,9 @@ trait Foldable[F[_]] extends UnorderedFoldable[F] with FoldableNFunctions[F] { s * scala> import cats.syntax.all._ * scala> def parseInt(s: String): Option[Int] = Either.catchOnly[NumberFormatException](s.toInt).toOption * scala> val F = Foldable[List] - * scala> F.traverse_(List("333", "444"))(parseInt) + * scala> F.traverseVoid(List("333", "444"))(parseInt) * res0: Option[Unit] = Some(()) - * scala> F.traverse_(List("333", "zzz"))(parseInt) + * scala> F.traverseVoid(List("333", "zzz"))(parseInt) * res1: Option[Unit] = None * }}} * @@ -588,17 +588,26 @@ trait Foldable[F[_]] extends UnorderedFoldable[F] with FoldableNFunctions[F] { s * or effect, and the specific `A` aspect of `G[A]` is not otherwise * needed. */ - def traverse_[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = + def traverseVoid[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = foldRight(fa, Always(G.unit)) { (a, acc) => G.map2Eval(f(a), acc) { (_, _) => () } }.value + /** + * Alias for `traverseVoid`. + * + * @deprecated this method should be considered as deprecated; + * refrain from using this method and consider switching to `traverseVoid`. + */ + def traverse_[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = + traverseVoid(fa)(f) + /** * Sequence `F[G[A]]` using `Applicative[G]`. * - * This is similar to `traverse_` except it operates on `F[G[A]]` + * This is similar to `traverseVoid` except it operates on `F[G[A]]` * values, so no additional functions are needed. * * For example: @@ -606,14 +615,23 @@ trait Foldable[F[_]] extends UnorderedFoldable[F] with FoldableNFunctions[F] { s * {{{ * scala> import cats.syntax.all._ * scala> val F = Foldable[List] - * scala> F.sequence_(List(Option(1), Option(2), Option(3))) + * scala> F.sequenceVoid(List(Option(1), Option(2), Option(3))) * res0: Option[Unit] = Some(()) - * scala> F.sequence_(List(Option(1), None, Option(3))) + * scala> F.sequenceVoid(List(Option(1), None, Option(3))) * res1: Option[Unit] = None * }}} */ + def sequenceVoid[G[_]: Applicative, A](fga: F[G[A]]): G[Unit] = + traverseVoid(fga)(identity) + + /** + * Alias for `sequenceVoid`. + * + * @deprecated this method should be considered as deprecated; + * refrain from using this method and consider switching to `sequenceVoid`. + */ def sequence_[G[_]: Applicative, A](fga: F[G[A]]): G[Unit] = - traverse_(fga)(identity) + sequenceVoid(fga) /** * Fold implemented using the given `MonoidK[G]` instance. @@ -1053,10 +1071,17 @@ object Foldable { typeClassInstance.foldMapM[G, A, B](self)(f)(G, B) def foldMapA[G[_], B](f: A => G[B])(implicit G: Applicative[G], B: Monoid[B]): G[B] = typeClassInstance.foldMapA[G, A, B](self)(f)(G, B) + def traverseVoid[G[_], B](f: A => G[B])(implicit G: Applicative[G]): G[Unit] = + typeClassInstance.traverseVoid[G, A, B](self)(f)(G) def traverse_[G[_], B](f: A => G[B])(implicit G: Applicative[G]): G[Unit] = - typeClassInstance.traverse_[G, A, B](self)(f)(G) + traverseVoid[G, B](f) + // TODO: looks like these two methods below duplicate the same named methods from `NestedFoldableOps`. + // Moreover, the other two methods take precedence, thereby these two are not in use whatsoever. + // Perhaps it makes sense to deprecate one pair of them either here or there. + def sequenceVoid[G[_], B](implicit ev$1: A <:< G[B], ev$2: Applicative[G]): G[Unit] = + typeClassInstance.sequenceVoid[G, B](self.asInstanceOf[F[G[B]]]) def sequence_[G[_], B](implicit ev$1: A <:< G[B], ev$2: Applicative[G]): G[Unit] = - typeClassInstance.sequence_[G, B](self.asInstanceOf[F[G[B]]]) + sequenceVoid[G, B] def foldK[G[_], B](implicit ev$1: A <:< G[B], G: MonoidK[G]): G[B] = typeClassInstance.foldK[G, B](self.asInstanceOf[F[G[B]]])(G) def find(f: A => Boolean): Option[A] = typeClassInstance.find[A](self)(f) diff --git a/core/src/main/scala/cats/syntax/foldable.scala b/core/src/main/scala/cats/syntax/foldable.scala index 861d61d1e9..b70eb71674 100644 --- a/core/src/main/scala/cats/syntax/foldable.scala +++ b/core/src/main/scala/cats/syntax/foldable.scala @@ -47,7 +47,10 @@ private[syntax] trait FoldableSyntaxBinCompat1 { } final class NestedFoldableOps[F[_], G[_], A](private val fga: F[G[A]]) extends AnyVal { - def sequence_(implicit F: Foldable[F], G: Applicative[G]): G[Unit] = F.sequence_(fga) + // TODO: looks like these two methods below duplicate the same named methods from `Foldable.Ops`. + // Perhaps it makes sense to deprecate one pair of them either here or there. + def sequenceVoid(implicit F: Foldable[F], G: Applicative[G]): G[Unit] = F.sequenceVoid(fga) + def sequence_(implicit F: Foldable[F], G: Applicative[G]): G[Unit] = sequenceVoid /** * @see [[Foldable.foldK]]. @@ -61,6 +64,8 @@ final class NestedFoldableOps[F[_], G[_], A](private val fga: F[G[A]]) extends A * res0: Set[Int] = Set(1, 2, 3, 4) * }}} */ + // TODO: looks like this method below duplicate the same named one from `Foldable.Ops`. + // Perhaps it makes sense to deprecate one of them. def foldK(implicit F: Foldable[F], G: MonoidK[G]): G[A] = F.foldK(fga) } From 25149a0896d36e42a9f43102bbb89f096a29b928 Mon Sep 17 00:00:00 2001 From: satorg Date: Tue, 26 Nov 2024 23:59:15 -0800 Subject: [PATCH 090/123] add `nonEmptyTraverse/SequenceVoid` to `Reducible` --- core/src/main/scala/cats/Reducible.scala | 39 ++++++++++++++++++------ 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/core/src/main/scala/cats/Reducible.scala b/core/src/main/scala/cats/Reducible.scala index 257e9e82f2..d34a2039b5 100644 --- a/core/src/main/scala/cats/Reducible.scala +++ b/core/src/main/scala/cats/Reducible.scala @@ -21,7 +21,6 @@ package cats -import cats.Foldable.Source import cats.data.{Ior, NonEmptyList} /** @@ -202,31 +201,49 @@ trait Reducible[F[_]] extends Foldable[F] { self => * `A` values will be mapped into `G[B]` and combined using * `Apply#map2`. * - * This method is similar to [[Foldable.traverse_]]. There are two + * This method is similar to [[Foldable.traverseVoid]]. There are two * main differences: * * 1. We only need an [[Apply]] instance for `G` here, since we * don't need to call [[Applicative.pure]] for a starting value. * 2. This performs a strict left-associative traversal and thus * must always traverse the entire data structure. Prefer - * [[Foldable.traverse_]] if you have an [[Applicative]] instance + * [[Foldable.traverseVoid]] if you have an [[Applicative]] instance * available for `G` and want to take advantage of short-circuiting * the traversal. */ - def nonEmptyTraverse_[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Apply[G]): G[Unit] = { + def nonEmptyTraverseVoid[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Apply[G]): G[Unit] = { val f1 = f.andThen(G.void) reduceRightTo(fa)(f1)((x, y) => G.map2Eval(f1(x), y)((_, b) => b)).value } + /** + * Alias for `nonEmptyTraverseVoid`. + * + * @deprecated this method should be considered as deprecated; + * refrain from using this method and consider switching to `nonEmptyTraverseVoid`. + */ + def nonEmptyTraverse_[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Apply[G]): G[Unit] = + nonEmptyTraverseVoid(fa)(f) + /** * Sequence `F[G[A]]` using `Apply[G]`. * - * This method is similar to [[Foldable.sequence_]] but requires only + * This method is similar to [[Foldable.sequenceVoid]] but requires only * an [[Apply]] instance for `G` instead of [[Applicative]]. See the - * [[nonEmptyTraverse_]] documentation for a description of the differences. + * [[nonEmptyTraverseVoid]] documentation for a description of the differences. + */ + def nonEmptySequenceVoid[G[_], A](fga: F[G[A]])(implicit G: Apply[G]): G[Unit] = + nonEmptyTraverseVoid(fga)(identity) + + /** + * Alias for `nonEmptySequenceVoid`. + * + * @deprecated this method should be considered as deprecated; + * refrain from using this method and consider switching to `nonEmptySequenceVoid`. */ def nonEmptySequence_[G[_], A](fga: F[G[A]])(implicit G: Apply[G]): G[Unit] = - nonEmptyTraverse_(fga)(identity) + nonEmptySequenceVoid(fga) def toNonEmptyList[A](fa: F[A]): NonEmptyList[A] = reduceRightTo(fa)(a => NonEmptyList(a, Nil)) { (a, lnel) => @@ -399,10 +416,14 @@ object Reducible { typeClassInstance.reduceMapM[G, A, B](self)(f)(G, B) def reduceRightTo[B](f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[B] = typeClassInstance.reduceRightTo[A, B](self)(f)(g) + def nonEmptyTraverseVoid[G[_], B](f: A => G[B])(implicit G: Apply[G]): G[Unit] = + typeClassInstance.nonEmptyTraverseVoid[G, A, B](self)(f) def nonEmptyTraverse_[G[_], B](f: A => G[B])(implicit G: Apply[G]): G[Unit] = - typeClassInstance.nonEmptyTraverse_[G, A, B](self)(f)(G) + nonEmptyTraverseVoid[G, B](f) + def nonEmptySequenceVoid[G[_], B](implicit ev$1: A <:< G[B], G: Apply[G]): G[Unit] = + typeClassInstance.nonEmptySequenceVoid[G, B](self.asInstanceOf[F[G[B]]]) def nonEmptySequence_[G[_], B](implicit ev$1: A <:< G[B], G: Apply[G]): G[Unit] = - typeClassInstance.nonEmptySequence_[G, B](self.asInstanceOf[F[G[B]]])(G) + nonEmptySequenceVoid[G, B] def toNonEmptyList: NonEmptyList[A] = typeClassInstance.toNonEmptyList[A](self) def minimum(implicit A: Order[A]): A = typeClassInstance.minimum[A](self)(A) def maximum(implicit A: Order[A]): A = typeClassInstance.maximum[A](self)(A) From f93efd5645bb4f4fea58235532aca871f151026f Mon Sep 17 00:00:00 2001 From: satorg Date: Sun, 3 Nov 2024 21:12:18 -0800 Subject: [PATCH 091/123] add `par*[Sequence/Traverse]Void` to `Parallel` --- core/src/main/scala/cats/Parallel.scala | 66 +++++++++++++++---- .../src/main/scala/cats/syntax/parallel.scala | 16 ++++- 2 files changed, 66 insertions(+), 16 deletions(-) diff --git a/core/src/main/scala/cats/Parallel.scala b/core/src/main/scala/cats/Parallel.scala index adbae65d68..ace905b3b8 100644 --- a/core/src/main/scala/cats/Parallel.scala +++ b/core/src/main/scala/cats/Parallel.scala @@ -260,25 +260,41 @@ object Parallel extends ParallelArityFunctions2 { } /** - * Like `Foldable[A].sequence_`, but uses the applicative instance + * Like `Foldable[A].sequenceVoid`, but uses the applicative instance * corresponding to the Parallel instance instead. */ - def parSequence_[T[_]: Foldable, M[_], A](tma: T[M[A]])(implicit P: Parallel[M]): M[Unit] = { - val fu: P.F[Unit] = Foldable[T].traverse_(tma)(P.parallel.apply(_))(P.applicative) + def parSequenceVoid[T[_]: Foldable, M[_], A](tma: T[M[A]])(implicit P: Parallel[M]): M[Unit] = { + val fu: P.F[Unit] = Foldable[T].traverseVoid(tma)(P.parallel.apply(_))(P.applicative) P.sequential(fu) } /** - * Like `Foldable[A].traverse_`, but uses the applicative instance + * Alias for `parSequenceVoid`. + * + * @deprecated this method should be considered as deprecated; + * refrain from using this method and consider switching to `parSequenceVoid`. + */ + def parSequence_[T[_]: Foldable, M[_], A](tma: T[M[A]])(implicit P: Parallel[M]): M[Unit] = + parSequenceVoid(tma) + + /** + * Like `Foldable[A].traverseVoid`, but uses the applicative instance * corresponding to the Parallel instance instead. */ - def parTraverse_[T[_]: Foldable, M[_], A, B]( - ta: T[A] - )(f: A => M[B])(implicit P: Parallel[M]): M[Unit] = { - val gtb: P.F[Unit] = Foldable[T].traverse_(ta)(a => P.parallel(f(a)))(P.applicative) + def parTraverseVoid[T[_]: Foldable, M[_], A, B](ta: T[A])(f: A => M[B])(implicit P: Parallel[M]): M[Unit] = { + val gtb: P.F[Unit] = Foldable[T].traverseVoid(ta)(a => P.parallel(f(a)))(P.applicative) P.sequential(gtb) } + /** + * Alias for `parTraverseVoid`. + * + * @deprecated this method should be considered as deprecated; + * refrain from using this method and consider switching to `parTraverseVoid`. + */ + def parTraverse_[T[_]: Foldable, M[_], A, B](ta: T[A])(f: A => M[B])(implicit P: Parallel[M]): M[Unit] = + parTraverseVoid(ta)(f) + def parUnorderedTraverse[T[_]: UnorderedTraverse, M[_], F[_]: CommutativeApplicative, A, B]( ta: T[A] )(f: A => M[B])(implicit P: Parallel.Aux[M, F]): M[T[B]] = @@ -345,27 +361,49 @@ object Parallel extends ParallelArityFunctions2 { } /** - * Like `Reducible[A].nonEmptySequence_`, but uses the apply instance + * Like `Reducible[A].nonEmptySequenceVoid`, but uses the apply instance * corresponding to the Parallel instance instead. */ - def parNonEmptySequence_[T[_]: Reducible, M[_], A]( + def parNonEmptySequenceVoid[T[_]: Reducible, M[_], A]( tma: T[M[A]] )(implicit P: NonEmptyParallel[M]): M[Unit] = { - val fu: P.F[Unit] = Reducible[T].nonEmptyTraverse_(tma)(P.parallel.apply(_))(P.apply) + val fu: P.F[Unit] = Reducible[T].nonEmptyTraverseVoid(tma)(P.parallel.apply(_))(P.apply) P.sequential(fu) } /** - * Like `Reducible[A].nonEmptyTraverse_`, but uses the apply instance + * Alias for `parNonEmptySequenceVoid`. + * + * @deprecated this method should be considered as deprecated; + * refrain from using this method and consider switching to `parNonEmptySequenceVoid`. + */ + def parNonEmptySequence_[T[_]: Reducible, M[_], A]( + tma: T[M[A]] + )(implicit P: NonEmptyParallel[M]): M[Unit] = + parNonEmptySequenceVoid[T, M, A](tma) + + /** + * Like `Reducible[A].nonEmptyTraverseVoid`, but uses the apply instance * corresponding to the Parallel instance instead. */ - def parNonEmptyTraverse_[T[_]: Reducible, M[_], A, B]( + def parNonEmptyTraverseVoid[T[_]: Reducible, M[_], A, B]( ta: T[A] )(f: A => M[B])(implicit P: NonEmptyParallel[M]): M[Unit] = { - val gtb: P.F[Unit] = Reducible[T].nonEmptyTraverse_(ta)(a => P.parallel(f(a)))(P.apply) + val gtb: P.F[Unit] = Reducible[T].nonEmptyTraverseVoid(ta)(a => P.parallel(f(a)))(P.apply) P.sequential(gtb) } + /** + * Alias for `parNonEmptyTraverseVoid`. + * + * @deprecated this method should be considered as deprecated; + * refrain from using this method and consider switching to `parNonEmptyTraverseVoid`. + */ + def parNonEmptyTraverse_[T[_]: Reducible, M[_], A, B]( + ta: T[A] + )(f: A => M[B])(implicit P: NonEmptyParallel[M]): M[Unit] = + parNonEmptyTraverseVoid[T, M, A, B](ta)(f) + /** * Like `Bitraverse[A].bitraverse`, but uses the applicative instance * corresponding to the Parallel instance instead. diff --git a/core/src/main/scala/cats/syntax/parallel.scala b/core/src/main/scala/cats/syntax/parallel.scala index 3624946c1b..f59fae17a8 100644 --- a/core/src/main/scala/cats/syntax/parallel.scala +++ b/core/src/main/scala/cats/syntax/parallel.scala @@ -108,9 +108,13 @@ trait ParallelTraverseFilterSyntax { } trait ParallelTraverseSyntax { + // Note: this could be renamed to `catsSyntaxParallelTraverseVoid` for consistency, + // but it looks like too much of a hassle of fighting binary compatibility issues for the implicit part of the API. implicit final def catsSyntaxParallelTraverse_[T[_]: Foldable, A](ta: T[A]): ParallelTraversable_Ops[T, A] = new ParallelTraversable_Ops(ta) + // Note: this could be renamed to `catsSyntaxParallelSequenceVoid` for consistency, + // but it looks like too much of a hassle of fighting binary compatibility issues for the implicit part of the API. implicit final def catsSyntaxParallelSequence_[T[_]: Foldable, M[_], A](tma: T[M[A]]): ParallelSequence_Ops[T, M, A] = new ParallelSequence_Ops(tma) } @@ -188,9 +192,13 @@ final class ParallelSequenceFilterOps[T[_], M[_], A](private val tmoa: T[M[Optio Parallel.parSequenceFilter(tmoa) } +// Note: this could be renamed to `ParallelTraversableVoidOps` for consistency, +// but it looks like too much of a hassle of fighting binary compatibility issues for the implicit part of the API. final class ParallelTraversable_Ops[T[_], A](private val ta: T[A]) extends AnyVal { + def parTraverseVoid[M[_], B](f: A => M[B])(implicit T: Foldable[T], P: Parallel[M]): M[Unit] = + Parallel.parTraverseVoid(ta)(f) def parTraverse_[M[_], B](f: A => M[B])(implicit T: Foldable[T], P: Parallel[M]): M[Unit] = - Parallel.parTraverse_(ta)(f) + parTraverseVoid(f) } @deprecated("Kept for binary compatibility", "2.6.0") @@ -217,9 +225,13 @@ final class ParallelSequenceOps1[T[_], M[_], A](private val tma: T[M[A]]) extend Parallel.parSequence(tma) } +// Note: this could be renamed to `ParallelSequenceVoidOps` for consistency, +// but it looks like too much of a hassle of fighting binary compatibility issues for the implicit part of the API. final class ParallelSequence_Ops[T[_], M[_], A](private val tma: T[M[A]]) extends AnyVal { + def parSequenceVoid(implicit T: Foldable[T], P: Parallel[M]): M[Unit] = + Parallel.parSequenceVoid(tma) def parSequence_(implicit T: Foldable[T], P: Parallel[M]): M[Unit] = - Parallel.parSequence_(tma) + parSequenceVoid } @deprecated("Kept for binary compatibility", "2.6.0") From 48526923b73f1ba31e8777390c4a7df6278a80b7 Mon Sep 17 00:00:00 2001 From: satorg Date: Sun, 3 Nov 2024 21:21:33 -0800 Subject: [PATCH 092/123] rename `traverse_Directly` to `traverseVoidDirectly` in `Traverse` --- core/src/main/scala/cats/Traverse.scala | 2 +- mima.sbt | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/Traverse.scala b/core/src/main/scala/cats/Traverse.scala index cc2993ee69..2e9df1ea84 100644 --- a/core/src/main/scala/cats/Traverse.scala +++ b/core/src/main/scala/cats/Traverse.scala @@ -296,7 +296,7 @@ object Traverse { } } - private[cats] def traverse_Directly[G[_], A, B]( + private[cats] def traverseVoidDirectly[G[_], A, B]( fa: IterableOnce[A] )(f: A => G[B])(implicit G: StackSafeMonad[G]): G[Unit] = { val iter = fa.iterator diff --git a/mima.sbt b/mima.sbt index 7b37117e57..4571afdc5c 100644 --- a/mima.sbt +++ b/mima.sbt @@ -157,5 +157,8 @@ ThisBuild / mimaBinaryIssueFilters ++= { ) ++ Seq( ProblemFilters.exclude[MissingClassProblem]("cats.compat.package"), ProblemFilters.exclude[MissingClassProblem]("cats.compat.package$") + ) ++ Seq( // PR#4682 + // Renamed to `cats.Traverse.traverseVoidDirectly` + ProblemFilters.exclude[DirectMissingMethodProblem]("cats.Traverse.traverse_Directly") ) } From 12403984b6ad4488846903325894bbc28d1a479d Mon Sep 17 00:00:00 2001 From: satorg Date: Sun, 3 Nov 2024 21:23:12 -0800 Subject: [PATCH 093/123] update data instances to `traverseVoid` --- core/src/main/scala-2.13+/cats/instances/arraySeq.scala | 4 ++-- core/src/main/scala/cats/data/Chain.scala | 4 ++-- core/src/main/scala/cats/instances/list.scala | 4 ++-- core/src/main/scala/cats/instances/queue.scala | 4 ++-- core/src/main/scala/cats/instances/seq.scala | 4 ++-- core/src/main/scala/cats/instances/vector.scala | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/src/main/scala-2.13+/cats/instances/arraySeq.scala b/core/src/main/scala-2.13+/cats/instances/arraySeq.scala index f41a781ad6..11201b309c 100644 --- a/core/src/main/scala-2.13+/cats/instances/arraySeq.scala +++ b/core/src/main/scala-2.13+/cats/instances/arraySeq.scala @@ -110,9 +110,9 @@ private[cats] object ArraySeqInstances { } - override def traverse_[G[_], A, B](fa: ArraySeq[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = + override def traverseVoid[G[_], A, B](fa: ArraySeq[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = G match { - case x: StackSafeMonad[G] => Traverse.traverse_Directly(fa)(f)(x) + case x: StackSafeMonad[G] => Traverse.traverseVoidDirectly(fa)(f)(x) case _ => foldRight(fa, Eval.now(G.unit)) { (a, acc) => G.map2Eval(f(a), acc) { (_, _) => diff --git a/core/src/main/scala/cats/data/Chain.scala b/core/src/main/scala/cats/data/Chain.scala index 2248a562ea..4558e63b26 100644 --- a/core/src/main/scala/cats/data/Chain.scala +++ b/core/src/main/scala/cats/data/Chain.scala @@ -1254,9 +1254,9 @@ sealed abstract private[data] class ChainInstances extends ChainInstances1 { }(f) } - override def traverse_[G[_], A, B](fa: Chain[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = + override def traverseVoid[G[_], A, B](fa: Chain[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = G match { - case x: StackSafeMonad[G] => Traverse.traverse_Directly(fa.iterator)(f)(x) + case x: StackSafeMonad[G] => Traverse.traverseVoidDirectly(fa.iterator)(f)(x) case _ => foldRight(fa, Eval.now(G.unit)) { (a, acc) => G.map2Eval(f(a), acc) { (_, _) => diff --git a/core/src/main/scala/cats/instances/list.scala b/core/src/main/scala/cats/instances/list.scala index a1306f159b..0b33e872a2 100644 --- a/core/src/main/scala/cats/instances/list.scala +++ b/core/src/main/scala/cats/instances/list.scala @@ -134,9 +134,9 @@ trait ListInstances extends cats.kernel.instances.ListInstances { /** * This avoids making a very deep stack by building a tree instead */ - override def traverse_[G[_], A, B](fa: List[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = { + override def traverseVoid[G[_], A, B](fa: List[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = { G match { - case x: StackSafeMonad[G] => Traverse.traverse_Directly(fa)(f)(x) + case x: StackSafeMonad[G] => Traverse.traverseVoidDirectly(fa)(f)(x) case _ => // the cost of this is O(size log size) // c(n) = n + 2 * c(n/2) = n + 2(n/2 log (n/2)) = n + n (logn - 1) = n log n diff --git a/core/src/main/scala/cats/instances/queue.scala b/core/src/main/scala/cats/instances/queue.scala index bb10850423..2bb6dd3aa9 100644 --- a/core/src/main/scala/cats/instances/queue.scala +++ b/core/src/main/scala/cats/instances/queue.scala @@ -134,9 +134,9 @@ trait QueueInstances extends cats.kernel.instances.QueueInstances { } } - override def traverse_[G[_], A, B](fa: Queue[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = + override def traverseVoid[G[_], A, B](fa: Queue[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = G match { - case x: StackSafeMonad[G] => Traverse.traverse_Directly(fa)(f)(x) + case x: StackSafeMonad[G] => Traverse.traverseVoidDirectly(fa)(f)(x) case _ => foldRight(fa, Eval.now(G.unit)) { (a, acc) => G.map2Eval(f(a), acc) { (_, _) => diff --git a/core/src/main/scala/cats/instances/seq.scala b/core/src/main/scala/cats/instances/seq.scala index 32272eb1f9..88e5a969c5 100644 --- a/core/src/main/scala/cats/instances/seq.scala +++ b/core/src/main/scala/cats/instances/seq.scala @@ -134,9 +134,9 @@ trait SeqInstances extends cats.kernel.instances.SeqInstances { G.map(Chain.traverseViaChain(fa.toIndexedSeq)(f))(_.toList) } - override def traverse_[G[_], A, B](fa: Seq[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = + override def traverseVoid[G[_], A, B](fa: Seq[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = G match { - case x: StackSafeMonad[G] => Traverse.traverse_Directly(fa)(f)(x) + case x: StackSafeMonad[G] => Traverse.traverseVoidDirectly(fa)(f)(x) case _ => foldRight(fa, Eval.now(G.unit)) { (a, acc) => G.map2Eval(f(a), acc) { (_, _) => diff --git a/core/src/main/scala/cats/instances/vector.scala b/core/src/main/scala/cats/instances/vector.scala index 06f93b4fef..b8f4f87dcd 100644 --- a/core/src/main/scala/cats/instances/vector.scala +++ b/core/src/main/scala/cats/instances/vector.scala @@ -140,9 +140,9 @@ trait VectorInstances extends cats.kernel.instances.VectorInstances { /** * This avoids making a very deep stack by building a tree instead */ - override def traverse_[G[_], A, B](fa: Vector[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = { + override def traverseVoid[G[_], A, B](fa: Vector[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = { G match { - case x: StackSafeMonad[G] => Traverse.traverse_Directly(fa)(f)(x) + case x: StackSafeMonad[G] => Traverse.traverseVoidDirectly(fa)(f)(x) case _ => // the cost of this is O(size) // c(n) = 1 + 2 * c(n/2) From eb77225c8c1657ba21e035eeffc2f60e4054cde8 Mon Sep 17 00:00:00 2001 From: satorg Date: Wed, 27 Nov 2024 00:19:26 -0800 Subject: [PATCH 094/123] update benchmarks --- .../src/main/scala/cats/bench/TraverseBench.scala | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/bench/src/main/scala/cats/bench/TraverseBench.scala b/bench/src/main/scala/cats/bench/TraverseBench.scala index 188b1f6a43..5c967db7b6 100644 --- a/bench/src/main/scala/cats/bench/TraverseBench.scala +++ b/bench/src/main/scala/cats/bench/TraverseBench.scala @@ -89,9 +89,10 @@ class TraverseBench { } } + // TODO: consider renaming to `traverseVoidList` @Benchmark - def traverse_List(bh: Blackhole) = { - val result = listT.traverse_(list) { i => + def traverse_List(bh: Blackhole): Unit = { + val result = listT.traverseVoid(list) { i => Eval.later { Blackhole.consumeCPU(Work) i * 2 @@ -155,9 +156,10 @@ class TraverseBench { bh.consume(result.value) } + // TODO: consider renaming to `traverseVoidVector` @Benchmark - def traverse_Vector(bh: Blackhole) = { - val result = vectorT.traverse_(vector) { i => + def traverse_Vector(bh: Blackhole): Unit = { + val result = vectorT.traverseVoid(vector) { i => Eval.later { Blackhole.consumeCPU(Work) i * 2 @@ -242,9 +244,10 @@ class TraverseBench { bh.consume(result.value) } + // TODO: consider renaming to `traverseVoidChain` @Benchmark - def traverse_Chain(bh: Blackhole) = { - val result = chainT.traverse_(chain) { i => + def traverse_Chain(bh: Blackhole): Unit = { + val result = chainT.traverseVoid(chain) { i => Eval.later { Blackhole.consumeCPU(Work) i * 2 From 2bb5233c4d326116b7faf1924f454180ba47553e Mon Sep 17 00:00:00 2001 From: satorg Date: Wed, 27 Nov 2024 00:48:05 -0800 Subject: [PATCH 095/123] update laws --- laws/src/main/scala/cats/laws/ReducibleLaws.scala | 4 ++-- laws/src/main/scala/cats/laws/discipline/ReducibleTests.scala | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/laws/src/main/scala/cats/laws/ReducibleLaws.scala b/laws/src/main/scala/cats/laws/ReducibleLaws.scala index c68b9a7f4a..8acd33462d 100644 --- a/laws/src/main/scala/cats/laws/ReducibleLaws.scala +++ b/laws/src/main/scala/cats/laws/ReducibleLaws.scala @@ -54,10 +54,10 @@ trait ReducibleLaws[F[_]] extends FoldableLaws[F] { fa.reduce <-> fa.reduceLeft(B.combine) def traverseConsistent[G[_]: Applicative, A, B](fa: F[A], f: A => G[B]): IsEq[G[Unit]] = - fa.nonEmptyTraverse_(f) <-> fa.traverse_(f) + fa.nonEmptyTraverseVoid(f) <-> fa.traverseVoid(f) def sequenceConsistent[G[_]: Applicative, A](fa: F[G[A]]): IsEq[G[Unit]] = - fa.nonEmptySequence_ <-> fa.sequence_ + fa.nonEmptySequenceVoid <-> fa.sequenceVoid def sizeConsistent[A](fa: F[A]): IsEq[Long] = fa.size <-> fa.reduceMap(_ => 1L) diff --git a/laws/src/main/scala/cats/laws/discipline/ReducibleTests.scala b/laws/src/main/scala/cats/laws/discipline/ReducibleTests.scala index 2de4e20681..b0a66a7f04 100644 --- a/laws/src/main/scala/cats/laws/discipline/ReducibleTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/ReducibleTests.scala @@ -58,8 +58,8 @@ trait ReducibleTests[F[_]] extends FoldableTests[F] { forAll(laws.reduceRightConsistentWithReduceRightOption[A] _), "reduce consistent with reduceLeft" -> forAll(laws.reduceReduceLeftConsistent[B] _), - "nonEmptyTraverse_ consistent with traverse_" -> forAll(laws.traverseConsistent[G, A, B] _), - "nonEmptySequence_ consistent with sequence_" -> forAll(laws.sequenceConsistent[G, A] _), + "nonEmptyTraverseVoid consistent with traverseVoid" -> forAll(laws.traverseConsistent[G, A, B] _), + "nonEmptySequenceVoid consistent with sequenceVoid" -> forAll(laws.sequenceConsistent[G, A] _), "size consistent with reduceMap" -> forAll(laws.sizeConsistent[A] _) ) } From 63111a1d2af88279cd428ad54705ce4c4e7ee2df Mon Sep 17 00:00:00 2001 From: satorg Date: Wed, 27 Nov 2024 00:52:15 -0800 Subject: [PATCH 096/123] update tests --- .../cats/tests/ScalaVersionSpecific.scala | 2 +- .../test/scala/cats/tests/KleisliSuite.scala | 10 +++---- .../test/scala/cats/tests/ParallelSuite.scala | 22 +++++++-------- .../scala/cats/tests/ReducibleSuite.scala | 4 +-- .../scala/cats/tests/RegressionSuite.scala | 10 +++---- .../test/scala/cats/tests/SyntaxSuite.scala | 27 +++++++++++++------ .../test/scala/cats/tests/TraverseSuite.scala | 4 +-- 7 files changed, 45 insertions(+), 34 deletions(-) diff --git a/tests/shared/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala b/tests/shared/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala index 1efbd376a0..0aa3bdd8fc 100644 --- a/tests/shared/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala +++ b/tests/shared/src/test/scala-2.13+/cats/tests/ScalaVersionSpecific.scala @@ -179,7 +179,7 @@ trait ScalaVersionSpecificRegressionSuite { self: RegressionSuite => // shouldn't have ever evaluated validate(8) checkAndResetCount(3) - assert(LazyList(1, 2, 6, 8).traverse_(validate) === (Either.left("6 is greater than 5"))) + assert(LazyList(1, 2, 6, 8).traverseVoid(validate) === Either.left("6 is greater than 5")) checkAndResetCount(3) } } diff --git a/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala b/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala index 56de674069..c7a8ec034c 100644 --- a/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/KleisliSuite.scala @@ -378,16 +378,16 @@ class KleisliSuite extends CatsSuite { assertEquals(program.run(A123), List((1, "2", true))) } - test("traverse_ doesn't stack overflow") { + test("traverseVoid doesn't stack overflow") { // see: https://github.com/typelevel/cats/issues/3947 - val resL = (1 to 10000).toList.traverse_(_ => Kleisli.liftF[Id, String, Unit](())).run("") - val resV = (1 to 10000).toVector.traverse_(_ => Kleisli.liftF[Id, String, Unit](())).run("") + val resL = (1 to 10000).toList.traverseVoid(_ => Kleisli.liftF[Id, String, Unit](())).run("") + val resV = (1 to 10000).toVector.traverseVoid(_ => Kleisli.liftF[Id, String, Unit](())).run("") assert(resL === resV) } - test("traverse_ doesn't stack overflow with List + Eval") { + test("traverseVoid doesn't stack overflow with List + Eval") { // see: https://github.com/typelevel/cats/issues/3947 - (1 to 10000).toList.traverse_(_ => Kleisli.liftF[Eval, String, Unit](Eval.Unit)).run("").value + (1 to 10000).toList.traverseVoid(_ => Kleisli.liftF[Eval, String, Unit](Eval.Unit)).run("").value } /** diff --git a/tests/shared/src/test/scala/cats/tests/ParallelSuite.scala b/tests/shared/src/test/scala/cats/tests/ParallelSuite.scala index 869b2611b5..4dc50a6d20 100644 --- a/tests/shared/src/test/scala/cats/tests/ParallelSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/ParallelSuite.scala @@ -78,24 +78,24 @@ class ParallelSuite } } - test("ParTraverse_ identity should be equivalent to parSequence_") { + test("ParTraverseVoid identity should be equivalent to parSequenceVoid") { forAll { (es: SortedSet[Either[String, Int]]) => - assert(Parallel.parTraverse_(es)(identity) === (Parallel.parSequence_[SortedSet, Either[String, *], Int](es))) + assert(Parallel.parTraverseVoid(es)(identity) === Parallel.parSequenceVoid[SortedSet, Either[String, *], Int](es)) } } - test("ParTraverse_ syntax should be equivalent to Parallel.parTraverse_") { + test("ParTraverseVoid syntax should be equivalent to Parallel.parTraverseVoid") { forAll { (es: SortedSet[Either[String, Int]]) => assert( - Parallel.parTraverse_[SortedSet, Either[String, *], Either[String, Int], Int](es)(identity) === (es - .parTraverse_(identity)) + Parallel.parTraverseVoid[SortedSet, Either[String, *], Either[String, Int], Int](es)(identity) === + es.parTraverseVoid(identity) ) } } - test("ParSequence_ syntax should be equivalent to Parallel.parSequence_") { + test("ParSequenceVoid syntax should be equivalent to Parallel.parSequenceVoid") { forAll { (es: SortedSet[Either[String, Int]]) => - assert(Parallel.parSequence_[SortedSet, Either[String, *], Int](es) === (es.parSequence_)) + assert(Parallel.parSequenceVoid[SortedSet, Either[String, *], Int](es) === es.parSequenceVoid) } } @@ -105,9 +105,9 @@ class ParallelSuite } } - test("ParNonEmptyTraverse_ identity should be equivalent to parNonEmptySequence_") { + test("ParNonEmptyTraverseVoid identity should be equivalent to parNonEmptySequenceVoid") { forAll { (es: NonEmptyList[Either[String, Int]]) => - assert(Parallel.parNonEmptyTraverse_(es)(identity) === (Parallel.parNonEmptySequence_(es))) + assert(Parallel.parNonEmptyTraverseVoid(es)(identity) === Parallel.parNonEmptySequenceVoid(es)) } } @@ -310,10 +310,10 @@ class ParallelSuite } } - test("ParReplicateA_ should be equivalent to fill parSequence_") { + test("ParReplicateA_ should be equivalent to fill parSequenceVoid") { forAll(Gen.choose(1, 20), Arbitrary.arbitrary[Either[String, String]]) { (repetitions: Int, e: Either[String, String]) => - assert(Parallel.parReplicateA_(repetitions, e) === Parallel.parSequence_(List.fill(repetitions)(e))) + assert(Parallel.parReplicateA_(repetitions, e) === Parallel.parSequenceVoid(List.fill(repetitions)(e))) } } diff --git a/tests/shared/src/test/scala/cats/tests/ReducibleSuite.scala b/tests/shared/src/test/scala/cats/tests/ReducibleSuite.scala index 01dd07fd02..a17a44e443 100644 --- a/tests/shared/src/test/scala/cats/tests/ReducibleSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/ReducibleSuite.scala @@ -234,11 +234,11 @@ abstract class ReducibleSuite[F[_]: Reducible](name: String)(implicit assert(out.toList === List(2, 4, 6, 9)) } - test(s"Reducible[$name].nonEmptyTraverse_ can breakout") { + test(s"Reducible[$name].nonEmptyTraverseVoid can breakout") { val notAllEven = fromValues(2, 4, 6, 9, 10, 12, 14) val out = mutable.ListBuffer[Int]() - notAllEven.nonEmptyTraverse_ { a => out += a; if (a % 2 == 0) Some(a) else None } + notAllEven.nonEmptyTraverseVoid { a => out += a; if (a % 2 == 0) Some(a) else None } assert(out.toList === List(2, 4, 6, 9)) } diff --git a/tests/shared/src/test/scala/cats/tests/RegressionSuite.scala b/tests/shared/src/test/scala/cats/tests/RegressionSuite.scala index b326f39c3b..2d852e2cb3 100644 --- a/tests/shared/src/test/scala/cats/tests/RegressionSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/RegressionSuite.scala @@ -162,23 +162,23 @@ class RegressionSuite extends CatsSuite with ScalaVersionSpecificRegressionSuite assert(Vector(1, 2, 6, 8).traverse(validate) === (Either.left("6 is greater than 5"))) checkAndResetCount(3) - assert(List(1, 2, 6, 8).traverse_(validate) === (Either.left("6 is greater than 5"))) + assert(List(1, 2, 6, 8).traverseVoid(validate) === Either.left("6 is greater than 5")) checkAndResetCount(3) { @annotation.nowarn("cat=deprecation") - val obtained = Stream(1, 2, 6, 8).traverse_(validate) + val obtained = Stream(1, 2, 6, 8).traverseVoid(validate) assert(obtained === Either.left("6 is greater than 5")) } checkAndResetCount(3) - assert(Vector(1, 2, 6, 8).traverse_(validate) === (Either.left("6 is greater than 5"))) + assert(Vector(1, 2, 6, 8).traverseVoid(validate) === Either.left("6 is greater than 5")) checkAndResetCount(3) - assert(NonEmptyList.of(1, 2, 6, 7, 8).traverse_(validate) === (Either.left("6 is greater than 5"))) + assert(NonEmptyList.of(1, 2, 6, 7, 8).traverseVoid(validate) === Either.left("6 is greater than 5")) checkAndResetCount(3) - assert(NonEmptyList.of(6, 7, 8).traverse_(validate) === (Either.left("6 is greater than 5"))) + assert(NonEmptyList.of(6, 7, 8).traverseVoid(validate) === Either.left("6 is greater than 5")) checkAndResetCount(1) } diff --git a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala index 2f8e82e4bd..2b7f19277d 100644 --- a/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/SyntaxSuite.scala @@ -39,7 +39,6 @@ import cats.data.{ ValidatedNec, ValidatedNel } -import cats.syntax.OptionOps import cats.syntax.all._ import scala.collection.immutable.{SortedMap, SortedSet} @@ -155,11 +154,11 @@ object SyntaxSuite { val a1: A = fz.foldMap(f3) val f4 = mock[A => G[B]] - val gu0: G[Unit] = fa.traverse_(f4) + val gu0: G[Unit] = fa.traverseVoid(f4) val fga = mock[F[G[A]]] - val gu1: G[Unit] = fga.sequence_ - val ga: G[A] = fga.foldK + val gu1: G[Unit] = fga.sequenceVoid // NestedFoldableOps + val ga1: G[A] = fga.foldK // NestedFoldableOps val f5 = mock[A => Boolean] val oa: Option[A] = fa.find(f5) @@ -201,7 +200,19 @@ object SyntaxSuite { val gunit: G[F[A]] = fga.nonEmptySequence } - def testParallel[M[_]: Parallel, T[_]: Traverse, A, B]: Unit = { + def testParallelFoldable[M[_]: Parallel, T[_]: Foldable, A, B](): Unit = { + val ta = mock[T[A]] + val tma = mock[T[M[A]]] + val famb = mock[A => M[B]] + + val mu1 = ta.parTraverseVoid(famb) + val mu2 = tma.parSequenceVoid + + // Suppress "unused local val" warnings and make sure the types were inferred correctly. + val _ = (mu1: M[Unit], mu2: M[Unit]) + } + + def testParallelTraverse[M[_]: Parallel, T[_]: Traverse, A, B](): Unit = { val ta = mock[T[A]] val f = mock[A => M[B]] val mtb = ta.parTraverse(f) @@ -348,7 +359,7 @@ object SyntaxSuite { val mtab2 = tmab.parLeftSequence } - def testParallelFoldable[T[_]: Foldable, M[_]: Parallel, A, B: Monoid]: Unit = { + def testParallelFoldableMonoid[T[_]: Foldable, M[_]: Parallel, A, B: Monoid](): Unit = { val ta = mock[T[A]] val f = mock[A => M[B]] val mb = ta.parFoldMapA(f) @@ -379,9 +390,9 @@ object SyntaxSuite { val lb: Eval[B] = fa.reduceRightTo(f4)(f6) val f7 = mock[A => G[B]] - val gu1: G[Unit] = fa.nonEmptyTraverse_(f7) + val gu1: G[Unit] = fa.nonEmptyTraverseVoid(f7) - val gu2: G[Unit] = fga.nonEmptySequence_ + val gu2: G[Unit] = fga.nonEmptySequenceVoid } def testFunctor[F[_]: Functor, A, B]: Unit = { diff --git a/tests/shared/src/test/scala/cats/tests/TraverseSuite.scala b/tests/shared/src/test/scala/cats/tests/TraverseSuite.scala index 94fffaea5e..1c6e8a1ad0 100644 --- a/tests/shared/src/test/scala/cats/tests/TraverseSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/TraverseSuite.scala @@ -83,9 +83,9 @@ abstract class TraverseSuite[F[_]: Traverse](name: String)(implicit ArbFInt: Arb } } - test(s"Traverse[$name].traverse matches traverse_ with Option") { + test(s"Traverse[$name].traverse matches traverseVoid with Option") { forAll { (fa: F[Int], fn: Int => Option[Int]) => - assert(Applicative[Option].void(fa.traverse(fn)) == fa.traverse_(fn)) + assert(Applicative[Option].void(fa.traverse(fn)) == fa.traverseVoid(fn)) } } From e8d95ee5083d3a4f0ae55ee6e9720d3c0fcad9d4 Mon Sep 17 00:00:00 2001 From: satorg Date: Tue, 17 Dec 2024 21:18:24 -0800 Subject: [PATCH 097/123] fix deprecation note in scaladocs --- core/src/main/scala/cats/Foldable.scala | 6 ++---- core/src/main/scala/cats/Parallel.scala | 12 ++++-------- core/src/main/scala/cats/Reducible.scala | 6 ++---- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/core/src/main/scala/cats/Foldable.scala b/core/src/main/scala/cats/Foldable.scala index e1fccb4a72..843ac1a25f 100644 --- a/core/src/main/scala/cats/Foldable.scala +++ b/core/src/main/scala/cats/Foldable.scala @@ -598,8 +598,7 @@ trait Foldable[F[_]] extends UnorderedFoldable[F] with FoldableNFunctions[F] { s /** * Alias for `traverseVoid`. * - * @deprecated this method should be considered as deprecated; - * refrain from using this method and consider switching to `traverseVoid`. + * @deprecated this method should be considered as deprecated and replaced by `traverseVoid`. */ def traverse_[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Applicative[G]): G[Unit] = traverseVoid(fa)(f) @@ -627,8 +626,7 @@ trait Foldable[F[_]] extends UnorderedFoldable[F] with FoldableNFunctions[F] { s /** * Alias for `sequenceVoid`. * - * @deprecated this method should be considered as deprecated; - * refrain from using this method and consider switching to `sequenceVoid`. + * @deprecated this method should be considered as deprecated and replaced by `sequenceVoid`. */ def sequence_[G[_]: Applicative, A](fga: F[G[A]]): G[Unit] = sequenceVoid(fga) diff --git a/core/src/main/scala/cats/Parallel.scala b/core/src/main/scala/cats/Parallel.scala index ace905b3b8..9b19eda831 100644 --- a/core/src/main/scala/cats/Parallel.scala +++ b/core/src/main/scala/cats/Parallel.scala @@ -271,8 +271,7 @@ object Parallel extends ParallelArityFunctions2 { /** * Alias for `parSequenceVoid`. * - * @deprecated this method should be considered as deprecated; - * refrain from using this method and consider switching to `parSequenceVoid`. + * @deprecated this method should be considered as deprecated and replaced by `parSequenceVoid`. */ def parSequence_[T[_]: Foldable, M[_], A](tma: T[M[A]])(implicit P: Parallel[M]): M[Unit] = parSequenceVoid(tma) @@ -289,8 +288,7 @@ object Parallel extends ParallelArityFunctions2 { /** * Alias for `parTraverseVoid`. * - * @deprecated this method should be considered as deprecated; - * refrain from using this method and consider switching to `parTraverseVoid`. + * @deprecated this method should be considered as deprecated and replaced by `parTraverseVoid`. */ def parTraverse_[T[_]: Foldable, M[_], A, B](ta: T[A])(f: A => M[B])(implicit P: Parallel[M]): M[Unit] = parTraverseVoid(ta)(f) @@ -374,8 +372,7 @@ object Parallel extends ParallelArityFunctions2 { /** * Alias for `parNonEmptySequenceVoid`. * - * @deprecated this method should be considered as deprecated; - * refrain from using this method and consider switching to `parNonEmptySequenceVoid`. + * @deprecated this method should be considered as deprecated and replaced by `parNonEmptySequenceVoid`. */ def parNonEmptySequence_[T[_]: Reducible, M[_], A]( tma: T[M[A]] @@ -396,8 +393,7 @@ object Parallel extends ParallelArityFunctions2 { /** * Alias for `parNonEmptyTraverseVoid`. * - * @deprecated this method should be considered as deprecated; - * refrain from using this method and consider switching to `parNonEmptyTraverseVoid`. + * @deprecated this method should be considered as deprecated and replaced by `parNonEmptyTraverseVoid`. */ def parNonEmptyTraverse_[T[_]: Reducible, M[_], A, B]( ta: T[A] diff --git a/core/src/main/scala/cats/Reducible.scala b/core/src/main/scala/cats/Reducible.scala index d34a2039b5..a51ba629b2 100644 --- a/core/src/main/scala/cats/Reducible.scala +++ b/core/src/main/scala/cats/Reducible.scala @@ -220,8 +220,7 @@ trait Reducible[F[_]] extends Foldable[F] { self => /** * Alias for `nonEmptyTraverseVoid`. * - * @deprecated this method should be considered as deprecated; - * refrain from using this method and consider switching to `nonEmptyTraverseVoid`. + * @deprecated this method should be considered as deprecated and replaced by `nonEmptyTraverseVoid`. */ def nonEmptyTraverse_[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Apply[G]): G[Unit] = nonEmptyTraverseVoid(fa)(f) @@ -239,8 +238,7 @@ trait Reducible[F[_]] extends Foldable[F] { self => /** * Alias for `nonEmptySequenceVoid`. * - * @deprecated this method should be considered as deprecated; - * refrain from using this method and consider switching to `nonEmptySequenceVoid`. + * @deprecated this method should be considered as deprecated and replaced by `nonEmptySequenceVoid`. */ def nonEmptySequence_[G[_], A](fga: F[G[A]])(implicit G: Apply[G]): G[Unit] = nonEmptySequenceVoid(fga) From c0ef9570ecfd369a407426cfe717ee7ab6449f1a Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 00:20:37 +0000 Subject: [PATCH 098/123] Update sbt-scalajs, scalajs-compiler, ... to 1.17.0 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 02e9d60e0b..d65cb27161 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -3,7 +3,7 @@ addSbtPlugin("org.typelevel" % "sbt-typelevel" % sbtTypelevelVersion) addSbtPlugin("org.typelevel" % "sbt-typelevel-site" % sbtTypelevelVersion) addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") addSbtPlugin("io.github.sbt-doctest" % "sbt-doctest" % "0.11.1") -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.17.0") addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.6") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.13.1") From a9b26d719354b9075c7a10aba830b46960dd16c2 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Mon, 23 Dec 2024 04:07:51 +0000 Subject: [PATCH 099/123] Update sbt, scripted-plugin to 1.10.7 --- project/build.properties | 2 +- scalafix/project/build.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/project/build.properties b/project/build.properties index e88a0d817d..73df629ac1 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.6 +sbt.version=1.10.7 diff --git a/scalafix/project/build.properties b/scalafix/project/build.properties index e88a0d817d..73df629ac1 100644 --- a/scalafix/project/build.properties +++ b/scalafix/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.6 +sbt.version=1.10.7 From 1926ba8050706f6c0fe39aef7a106968af68197b Mon Sep 17 00:00:00 2001 From: Georgi Krastev Date: Sat, 17 Sep 2022 23:26:37 +0200 Subject: [PATCH 100/123] Use helper functions in generated code --- project/Boilerplate.scala | 87 ++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 51 deletions(-) diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index 277a967cd6..58955aa3c4 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -61,9 +61,7 @@ object Boilerplate { val synTypedVals = synVals.zip(synTypes).map { case (v, t) => v + ":" + t } val `A..N` = synTypes.mkString(", ") val `a..n` = synVals.mkString(", ") - val `_.._` = Seq.fill(arity)("_").mkString(", ") val `(A..N)` = if (arity == 1) "Tuple1[A0]" else synTypes.mkString("(", ", ", ")") - val `(_.._)` = if (arity == 1) "Tuple1[_]" else Seq.fill(arity)("_").mkString("(", ", ", ")") val `(a..n)` = if (arity == 1) "Tuple1(a)" else synVals.mkString("(", ", ", ")") val `a:A..n:N` = synTypedVals.mkString(", ") @@ -285,11 +283,10 @@ object Boilerplate { def content(tv: TemplateVals) = { import tv._ - val tpes = synTypes.map { tpe => - s"F[$tpe]" - } - val fargs = (0 until arity).map("f" + _) - val fparams = fargs.zip(tpes).map { case (v, t) => s"$v:$t" }.mkString(", ") + val vals = (0 until arity).map("f" + _) + val tpes = synTypes.map(tpe => s"F[$tpe]") + val fargs = vals.mkString(", ") + val fparams = vals.zip(tpes).map { case (v, t) => s"$v:$t" }.mkString(", ") block""" |package cats @@ -303,7 +300,8 @@ object Boilerplate { | */ |trait FlatMapArityFunctions[F[_]] { self: FlatMap[F] => - /** @group FlatMapArity */ - - def flatMap$arity[${`A..N`}, Z]($fparams)(f: (${`A..N`}) => F[Z]): F[Z] = self.flatten(self.map$arity($fparams)(f)) + - def flatMap$arity[${`A..N`}, Z]($fparams)(f: (${`A..N`}) => F[Z]): F[Z] = + - flatten(map$arity($fargs)(f)) |} """ } @@ -356,12 +354,10 @@ object Boilerplate { def content(tv: TemplateVals) = { import tv._ - val tpes = synTypes.map { tpe => - s"M[$tpe]" - } - val fargs = (0 until arity).map("m" + _) - val fparams = fargs.zip(tpes).map { case (v, t) => s"$v:$t" }.mkString(", ") - val nestedExpansion = ParallelNestedExpansions(arity) + val vals = (0 until arity).map("m" + _) + val tpes = synTypes.map(tpe => s"M[$tpe]") + val fargs = vals.mkString(", ") + val fparams = vals.zip(tpes).map { case (v, t) => s"$v:$t" }.mkString(", ") block""" |package cats @@ -376,7 +372,7 @@ object Boilerplate { |abstract class ParallelArityFunctions2 extends ParallelArityFunctions { - /** @group ParTupleArity */ - def parTuple$arity[M[_], ${`A..N`}]($fparams)(implicit p: NonEmptyParallel[M]): M[(${`A..N`})] = - - p.flatMap.map(${nestedExpansion.products}) { case ${nestedExpansion.`(a..n)`} => (${`a..n`}) } + - parMap$arity($fargs)(Tuple$arity.apply) |} """ } @@ -438,7 +434,7 @@ object Boilerplate { - invariant.imap($nestedProducts) { case ${`nested (a..n)`} => f(${`a..n`}) } { z => val ${`(a..n)`} = g(z); ${`nested (a..n)`} } - /** @group TupleArity */ - def tuple$arity[F[_], ${`A..N`}]($fparams)(implicit semigroupal: Semigroupal[F], invariant: Invariant[F]):F[(${`A..N`})] = - - imap$arity($fargsS)((${`_.._`}))(identity) + - imap$arity($fargsS)(Tuple$arity.apply)(identity) - /** @group TraverseArity */ - def traverse$arity[F[_], G[_], ${`A..N`}, Z]($fparams)(f: (${`A..N`}) => G[Z])(implicit semigroupal: Semigroupal[F], traverse: Traverse[F], applicative: Applicative[G]): G[F[Z]] = - traverse.traverse($nestedProducts) { case ${`nested (a..n)`} => f(${`a..n`}) } @@ -453,14 +449,9 @@ object Boilerplate { def content(tv: TemplateVals) = { import tv._ - val tpes = synTypes.map { tpe => - s"M[$tpe]" - } - val tpesString = tpes.mkString(", ") - - val tuple = s"Tuple$arity[$tpesString]" - val tupleTpe = s"t$arity: $tuple" - val tupleArgs = (1 to arity).map(n => s"t$arity._$n").mkString(", ") + val tpes = synTypes.map(tpe => s"M[$tpe]") + val tuple = if (arity == 1) s"Tuple1[${tpes.head}]" else tpes.mkString("(", ", ", ")") + val tupleArgs = (1 to arity).map(n => s"t._$n").mkString(", ") val parMap = if (arity == 1) @@ -475,8 +466,7 @@ object Boilerplate { s"def parFlatMapN[Z](f: (${`A..N`}) => M[Z])(implicit p: NonEmptyParallel[M]): M[Z] = Parallel.parFlatMap$arity($tupleArgs)(f)" val parTupled = if (arity == 1) "" - else - s"def parTupled(implicit p: NonEmptyParallel[M]): M[(${`A..N`})] = Parallel.parTuple$arity($tupleArgs)" + else s"def parTupled(implicit p: NonEmptyParallel[M]): M[(${`A..N`})] = Parallel.parTuple$arity($tupleArgs)" block""" |package cats @@ -485,10 +475,10 @@ object Boilerplate { |import cats.Parallel | |trait TupleParallelSyntax { - - implicit def catsSyntaxTuple${arity}Parallel[M[_], ${`A..N`}]($tupleTpe): Tuple${arity}ParallelOps[M, ${`A..N`}] = new Tuple${arity}ParallelOps(t$arity) + - implicit def catsSyntaxTuple${arity}Parallel[M[_], ${`A..N`}](t: $tuple): Tuple${arity}ParallelOps[M, ${`A..N`}] = new Tuple${arity}ParallelOps(t) |} | - -private[syntax] final class Tuple${arity}ParallelOps[M[_], ${`A..N`}](private val $tupleTpe) extends Serializable { + -private[syntax] final class Tuple${arity}ParallelOps[M[_], ${`A..N`}](private val t: $tuple) extends Serializable { - $parMap - $parTupled - $parFlatMap @@ -504,20 +494,10 @@ object Boilerplate { def content(tv: TemplateVals) = { import tv._ - val tpes = synTypes.map { tpe => - s"F[$tpe]" - } - val tpesString = tpes.mkString(", ") - - val tuple = s"Tuple$arity[$tpesString]" - val tupleTpe = s"t$arity: $tuple" - val tupleArgs = (1 to arity).map(n => s"t$arity._$n").mkString(", ") - - val n = if (arity == 1) { - "" - } else { - arity.toString - } + val tpes = synTypes.map(tpe => s"F[$tpe]") + val tuple = if (arity == 1) s"Tuple1[${tpes.head}]" else tpes.mkString("(", ", ", ")") + val tupleArgs = (1 to arity).map(n => s"t._$n").mkString(", ") + val n = if (arity == 1) "" else arity.toString val map = if (arity == 1) @@ -537,11 +517,10 @@ object Boilerplate { else s"def imapN[Z](f: (${`A..N`}) => Z)(g: Z => (${`A..N`}))(implicit invariant: Invariant[F], semigroupal: Semigroupal[F]): F[Z] = Semigroupal.imap$arity($tupleArgs)(f)(g)" - val tupled = if (arity != 1) { - s"def tupled(implicit invariant: Invariant[F], semigroupal: Semigroupal[F]): F[(${`A..N`})] = Semigroupal.tuple$n($tupleArgs)" - } else { - "" - } + val tupled = + if (arity == 1) "" + else + s"def tupled(implicit invariant: Invariant[F], semigroupal: Semigroupal[F]): F[(${`A..N`})] = Semigroupal.tuple$n($tupleArgs)" val traverse = if (arity == 1) @@ -555,22 +534,25 @@ object Boilerplate { else s"def flatMapN[Z](f: (${`A..N`}) => F[Z])(implicit flatMap: FlatMap[F]): F[Z] = flatMap.flatMap$arity($tupleArgs)(f)" + val apWith = + s"def apWith[Z](f: F[(${`A..N`}) => Z])(implicit apply: Apply[F]): F[Z] = apply.ap$n(f)($tupleArgs)" + block""" |package cats |package syntax | |trait TupleSemigroupalSyntax { - - implicit def catsSyntaxTuple${arity}Semigroupal[F[_], ${`A..N`}]($tupleTpe): Tuple${arity}SemigroupalOps[F, ${`A..N`}] = new Tuple${arity}SemigroupalOps(t$arity) + - implicit def catsSyntaxTuple${arity}Semigroupal[F[_], ${`A..N`}](t: $tuple): Tuple${arity}SemigroupalOps[F, ${`A..N`}] = new Tuple${arity}SemigroupalOps(t) |} | - -private[syntax] final class Tuple${arity}SemigroupalOps[F[_], ${`A..N`}](private val $tupleTpe) extends Serializable { + -private[syntax] final class Tuple${arity}SemigroupalOps[F[_], ${`A..N`}](private val t: $tuple) extends Serializable { - $map - $contramap - $imap - $flatMap - $tupled - $traverse - - def apWith[Z](f: F[(${`A..N`}) => Z])(implicit apply: Apply[F]): F[Z] = apply.ap$n(f)($tupleArgs) + - $apWith -} | """ @@ -615,9 +597,12 @@ object Boilerplate { | * | */ |trait FoldableNFunctions[F[_]] { self: Foldable[F] => + | private def slidingN[A, B](fa: F[A], n: Int)(f: Seq[A] => B) = + | toIterable(fa).iterator.sliding(n).withPartial(false).map(f).toList + | - /** @group FoldableSlidingN */ - def sliding$arity[A](fa: F[A]): List[$tupleTpe] = - - toIterable(fa).iterator.sliding($arity).withPartial(false).map(x => $tupleXN).toList + - slidingN(fa, $arity)(x => $tupleXN) |} """ } From 291ef19ef212a07dbc4f08c7b248ae6df932f910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionu=C8=9B=20G=2E=20Stan?= Date: Mon, 17 Jun 2024 14:40:12 +0300 Subject: [PATCH 101/123] Add `intercalate` on the Semigroup companion object --- kernel/src/main/scala/cats/kernel/Semigroup.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/src/main/scala/cats/kernel/Semigroup.scala b/kernel/src/main/scala/cats/kernel/Semigroup.scala index e861f481fe..cc96528c90 100644 --- a/kernel/src/main/scala/cats/kernel/Semigroup.scala +++ b/kernel/src/main/scala/cats/kernel/Semigroup.scala @@ -178,6 +178,9 @@ object Semigroup */ @inline def last[A]: Semigroup[A] = (_, y) => y + @inline def intercalate[A](sep: A)(implicit ev: Semigroup[A]): Semigroup[A] = + ev.intercalate(sep) + implicit def catsKernelBoundedSemilatticeForBitSet: BoundedSemilattice[BitSet] = cats.kernel.instances.bitSet.catsKernelStdSemilatticeForBitSet implicit def catsKernelInstancesForUnit: BoundedSemilattice[Unit] with CommutativeGroup[Unit] = From 86526b4c8487c645c896b0f8c23f50c28765ba49 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 16:06:09 +0000 Subject: [PATCH 102/123] Update munit to 1.0.3 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 8dfba21b7e..8779410704 100644 --- a/build.sbt +++ b/build.sbt @@ -6,7 +6,7 @@ val disciplineVersion = "1.7.0" val disciplineMunitVersion = "2.0.0" -val munitVersion = "1.0.2" +val munitVersion = "1.0.3" val PrimaryJava = JavaSpec.temurin("8") val LTSJava = JavaSpec.temurin("17") From ea7688b5511f158a3489b40f096de0aed5187aa8 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Fri, 27 Dec 2024 20:07:36 +0000 Subject: [PATCH 103/123] Update sbt-typelevel, sbt-typelevel-site to 0.7.5 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index d65cb27161..a78d755e67 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,4 @@ -val sbtTypelevelVersion = "0.7.4" +val sbtTypelevelVersion = "0.7.5" addSbtPlugin("org.typelevel" % "sbt-typelevel" % sbtTypelevelVersion) addSbtPlugin("org.typelevel" % "sbt-typelevel-site" % sbtTypelevelVersion) addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") From 5b2e2ee218c1a7305135e0248397121861ecff0c Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Fri, 27 Dec 2024 20:09:13 +0000 Subject: [PATCH 104/123] Run prePR with sbt-typelevel Executed command: sbt tlPrePrBotHook --- .github/workflows/ci.yml | 50 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8740ddae2d..e7f4fc611d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,10 +24,10 @@ concurrency: jobs: build: - name: Build and Test + name: Test strategy: matrix: - os: [ubuntu-latest] + os: [ubuntu-22.04] scala: [2.12, 2.13, 3] java: [temurin@8, temurin@17, graalvm@21] project: [catsNative, catsJS, catsJVM] @@ -51,14 +51,14 @@ jobs: runs-on: ${{ matrix.os }} timeout-minutes: 60 steps: - - name: Install sbt - uses: sbt/setup-sbt@v1 - - name: Checkout current branch (full) uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Setup sbt + uses: sbt/setup-sbt@v1 + - name: Setup Java (temurin@8) id: setup-java-temurin-8 if: matrix.java == 'temurin@8' @@ -102,7 +102,7 @@ jobs: run: sbt githubWorkflowCheck - name: Check headers and formatting - if: matrix.java == 'temurin@8' && matrix.os == 'ubuntu-latest' + if: matrix.java == 'temurin@8' && matrix.os == 'ubuntu-22.04' run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' headerCheckAll scalafmtCheckAll 'project /' scalafmtSbtCheck - name: nativeLink @@ -117,11 +117,11 @@ jobs: run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' test - name: Check binary compatibility - if: matrix.java == 'temurin@8' && matrix.os == 'ubuntu-latest' + if: matrix.java == 'temurin@8' && matrix.os == 'ubuntu-22.04' run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' mimaReportBinaryIssues - name: Generate API documentation - if: matrix.java == 'temurin@8' && matrix.os == 'ubuntu-latest' + if: matrix.java == 'temurin@8' && matrix.os == 'ubuntu-22.04' run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' doc - name: Make target directories @@ -145,18 +145,18 @@ jobs: if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') strategy: matrix: - os: [ubuntu-latest] + os: [ubuntu-22.04] java: [temurin@8] runs-on: ${{ matrix.os }} steps: - - name: Install sbt - uses: sbt/setup-sbt@v1 - - name: Checkout current branch (full) uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Setup sbt + uses: sbt/setup-sbt@v1 + - name: Setup Java (temurin@8) id: setup-java-temurin-8 if: matrix.java == 'temurin@8' @@ -315,18 +315,18 @@ jobs: if: github.event.repository.fork == false && github.event_name != 'pull_request' strategy: matrix: - os: [ubuntu-latest] + os: [ubuntu-22.04] java: [temurin@8] runs-on: ${{ matrix.os }} steps: - - name: Install sbt - uses: sbt/setup-sbt@v1 - - name: Checkout current branch (full) uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Setup sbt + uses: sbt/setup-sbt@v1 + - name: Setup Java (temurin@8) id: setup-java-temurin-8 if: matrix.java == 'temurin@8' @@ -376,7 +376,7 @@ jobs: name: Validate Steward Config strategy: matrix: - os: [ubuntu-latest] + os: [ubuntu-22.04] java: [temurin@11] runs-on: ${{ matrix.os }} steps: @@ -401,18 +401,18 @@ jobs: name: Generate Site strategy: matrix: - os: [ubuntu-latest] + os: [ubuntu-22.04] java: [temurin@17] runs-on: ${{ matrix.os }} steps: - - name: Install sbt - uses: sbt/setup-sbt@v1 - - name: Checkout current branch (full) uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Setup sbt + uses: sbt/setup-sbt@v1 + - name: Setup Java (temurin@8) id: setup-java-temurin-8 if: matrix.java == 'temurin@8' @@ -467,18 +467,18 @@ jobs: name: Scalafix strategy: matrix: - os: [ubuntu-latest] + os: [ubuntu-22.04] java: [temurin@8] runs-on: ${{ matrix.os }} steps: - - name: Install sbt - uses: sbt/setup-sbt@v1 - - name: Checkout current branch (full) uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Setup sbt + uses: sbt/setup-sbt@v1 + - name: Setup Java (temurin@8) id: setup-java-temurin-8 if: matrix.java == 'temurin@8' From 5c84daa942693d03882f0f22c31a07620b9dc262 Mon Sep 17 00:00:00 2001 From: Daniel Urban Date: Sun, 29 Dec 2024 11:16:40 +0100 Subject: [PATCH 105/123] Override Foldable#toIterable for Chain --- core/src/main/scala/cats/data/Chain.scala | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/src/main/scala/cats/data/Chain.scala b/core/src/main/scala/cats/data/Chain.scala index 7f66961d4d..c93a1719e9 100644 --- a/core/src/main/scala/cats/data/Chain.scala +++ b/core/src/main/scala/cats/data/Chain.scala @@ -1265,6 +1265,11 @@ sealed abstract private[data] class ChainInstances extends ChainInstances1 { }.value } + final override def toIterable[A](fa: Chain[A]): Iterable[A] = new scala.collection.AbstractIterable[A] { + final override def iterator: Iterator[A] = + fa.iterator + } + override def mapAccumulate[S, A, B](init: S, fa: Chain[A])(f: (S, A) => (S, B)): (S, Chain[B]) = StaticMethods.mapAccumulateFromStrictFunctor(init, fa, f)(this) From 3b2c4bd70cbf218c2ac70df859d078cb7a39de37 Mon Sep 17 00:00:00 2001 From: "P. Oscar Boykin" Date: Thu, 2 Jan 2025 17:05:11 -1000 Subject: [PATCH 106/123] Add take/takeRight/drop/dropRight to Chain --- core/src/main/scala/cats/data/Chain.scala | 164 ++++++++++++++++++ .../test/scala/cats/tests/ChainSuite.scala | 23 +++ 2 files changed, 187 insertions(+) diff --git a/core/src/main/scala/cats/data/Chain.scala b/core/src/main/scala/cats/data/Chain.scala index c93a1719e9..bb803c9a92 100644 --- a/core/src/main/scala/cats/data/Chain.scala +++ b/core/src/main/scala/cats/data/Chain.scala @@ -256,6 +256,90 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { result } + /** + * take a certain amount of items from the front of the Chain + */ + final def take(count: Int): Chain[A] = { + // invariant count >= 1 + @tailrec + def go(lhs: Chain[A], count: Int, arg: Chain[A], rhs: Chain[A]): Chain[A] = + arg match { + case Wrap(seq) => + if (count == 1) { + lhs.append(seq(0)) + } else { + // count > 1 + val taken = seq.take(count) + // we may have not takeped all of count + val newCount = count - taken.length + val newLhs = lhs.concat(Wrap(taken)) + if (newCount > 0) { + // we have to keep takeping on the rhs + go(newLhs, newCount, rhs, Chain.nil) + } else { + // newCount == 0, we have taken enough + newLhs + } + } + case Append(l, r) => + go(lhs, count, l, r.concat(rhs)) + case s @ Singleton(_) => + // due to the invariant count >= 1 + val newLhs = if (lhs.isEmpty) s else Append(lhs, s) + if (count > 1) { + go(newLhs, count - 1, rhs, Chain.nil) + } else newLhs + case Empty => + if (rhs.isEmpty) lhs + else go(lhs, count, rhs, Chain.nil) + } + + if (count <= 0) Empty + else go(Empty, count, this, Empty) + } + + /** + * take a certain amount of items from the back of the Chain + */ + final def takeRight(count: Int): Chain[A] = { + // invariant count >= 1 + @tailrec + def go(lhs: Chain[A], count: Int, arg: Chain[A], rhs: Chain[A]): Chain[A] = + arg match { + case Wrap(seq) => + if (count == 1) { + lhs.append(seq.last) + } else { + // count > 1 + val taken = seq.takeRight(count) + // we may have not takeped all of count + val newCount = count - taken.length + val newRhs = Wrap(taken).concat(rhs) + if (newCount > 0) { + // we have to keep takeping on the rhs + go(Chain.nil, newCount, lhs, newRhs) + } else { + // newCount == 0, we have taken enough + newRhs + } + } + case Append(l, r) => + go(lhs.concat(l), count, r, rhs) + case s @ Singleton(_) => + // due to the invariant count >= 1 + val newRhs = if (rhs.isEmpty) s else Append(s, rhs) + if (count > 1) { + go(Empty, count - 1, lhs, newRhs) + } else newRhs + case Empty => + if (lhs.isEmpty) rhs + else go(Chain.nil, count, lhs, rhs) + } + + if (count <= 0) Empty + else go(Empty, count, this, Empty) + } + /** * Drops longest prefix of elements that satisfy a predicate. * @@ -275,6 +359,86 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { go(this) } + /** + * Drop a certain amount of items from the front of the Chain + */ + final def drop(count: Int): Chain[A] = { + // invariant count >= 1 + @tailrec + def go(count: Int, arg: Chain[A], rhs: Chain[A]): Chain[A] = + arg match { + case Wrap(seq) => + val dropped = seq.drop(count) + if (dropped.isEmpty) { + // we may have not dropped all of count + val newCount = count - seq.length + if (newCount > 0) { + // we have to keep dropping on the rhs + go(newCount, rhs, Chain.nil) + } else { + // we know that count >= seq.length else we wouldn't be empty + // so in this case, it is exactly count == seq.length + rhs + } + } else { + // we must be done + Chain.fromSeq(dropped).concat(rhs) + } + case Append(l, r) => + go(count, l, r.concat(rhs)) + case Singleton(_) => + // due to the invariant count >= 1 + if (count > 1) go(count - 1, rhs, Chain.nil) + else rhs + case Empty => + if (rhs.isEmpty) Empty + else go(count, rhs, Chain.nil) + } + + if (count <= 0) this + else go(count, this, Empty) + } + + /** + * Drop a certain amount of items from the back of the Chain + */ + final def dropRight(count: Int): Chain[A] = { + // invariant count >= 1 + @tailrec + def go(lhs: Chain[A], count: Int, arg: Chain[A]): Chain[A] = + arg match { + case Wrap(seq) => + val dropped = seq.dropRight(count) + if (dropped.isEmpty) { + // we may have not dropped all of count + val newCount = count - seq.length + if (newCount > 0) { + // we have to keep dropping on the rhs + go(Chain.nil, newCount, lhs) + } else { + // we know that count >= seq.length else we wouldn't be empty + // so in this case, it is exactly count == seq.length + lhs + } + } else { + // we must be done + lhs.concat(Chain.fromSeq(dropped)) + } + case Append(l, r) => + go(lhs.concat(l), count, r) + case Singleton(_) => + // due to the invariant count >= 1 + if (count > 1) go(Chain.nil, count - 1, lhs) + else lhs + case Empty => + if (lhs.isEmpty) Empty + else go(Chain.nil, count, lhs) + } + + if (count <= 0) this + else go(Empty, count, this) + } + /** * Folds over the elements from right to left using the supplied initial value and function. */ diff --git a/tests/shared/src/test/scala/cats/tests/ChainSuite.scala b/tests/shared/src/test/scala/cats/tests/ChainSuite.scala index 4a920ad4c4..7794823bfd 100644 --- a/tests/shared/src/test/scala/cats/tests/ChainSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/ChainSuite.scala @@ -448,4 +448,27 @@ class ChainSuite extends CatsSuite { assert(chain.foldRight(init)(fn) == chain.toList.foldRight(init)(fn)) } } + + test("drop(cnt).toList == toList.drop(cnt)") { + forAll { (chain: Chain[Int], count: Int) => + assert(chain.drop(count).toList == chain.toList.drop(count)) + } + } + + test("dropRight(cnt).toList == toList.dropRight(cnt)") { + forAll { (chain: Chain[Int], count: Int) => + assert(chain.dropRight(count).toList == chain.toList.dropRight(count)) + } + } + test("take(cnt).toList == toList.take(cnt)") { + forAll { (chain: Chain[Int], count: Int) => + assert(chain.take(count).toList == chain.toList.take(count)) + } + } + + test("takeRight(cnt).toList == toList.takeRight(cnt)") { + forAll { (chain: Chain[Int], count: Int) => + assert(chain.takeRight(count).toList == chain.toList.takeRight(count)) + } + } } From 83fe74c3567c2c99d4e9e3802a5f59281a082df9 Mon Sep 17 00:00:00 2001 From: "P. Oscar Boykin" Date: Thu, 2 Jan 2025 18:06:34 -1000 Subject: [PATCH 107/123] fix bug, improve scalachecks --- core/src/main/scala/cats/data/Chain.scala | 27 ++++++++++++------- .../test/scala/cats/tests/ChainSuite.scala | 19 ++++++++++--- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/core/src/main/scala/cats/data/Chain.scala b/core/src/main/scala/cats/data/Chain.scala index bb803c9a92..262beaaf87 100644 --- a/core/src/main/scala/cats/data/Chain.scala +++ b/core/src/main/scala/cats/data/Chain.scala @@ -266,13 +266,15 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { arg match { case Wrap(seq) => if (count == 1) { - lhs.append(seq(0)) + lhs.append(seq.head) } else { // count > 1 val taken = seq.take(count) // we may have not takeped all of count val newCount = count - taken.length - val newLhs = lhs.concat(Wrap(taken)) + val wrapped = Wrap(taken) + // this is more efficient than using concat + val newLhs = if (lhs.isEmpty) wrapped else Append(lhs, wrapped) if (newCount > 0) { // we have to keep takeping on the rhs go(newLhs, newCount, rhs, Chain.nil) @@ -282,7 +284,7 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { } } case Append(l, r) => - go(lhs, count, l, r.concat(rhs)) + go(lhs, count, l, if (rhs.isEmpty) r else Append(r, rhs)) case s @ Singleton(_) => // due to the invariant count >= 1 val newLhs = if (lhs.isEmpty) s else Append(lhs, s) @@ -308,13 +310,14 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { arg match { case Wrap(seq) => if (count == 1) { - lhs.append(seq.last) + seq.last +: rhs } else { // count > 1 val taken = seq.takeRight(count) // we may have not takeped all of count val newCount = count - taken.length - val newRhs = Wrap(taken).concat(rhs) + val wrapped = Wrap(taken) + val newRhs = if (rhs.isEmpty) wrapped else Append(wrapped, rhs) if (newCount > 0) { // we have to keep takeping on the rhs go(Chain.nil, newCount, lhs, newRhs) @@ -324,7 +327,7 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { } } case Append(l, r) => - go(lhs.concat(l), count, r, rhs) + go(if (lhs.isEmpty) l else Append(lhs, l), count, r, rhs) case s @ Singleton(_) => // due to the invariant count >= 1 val newRhs = if (rhs.isEmpty) s else Append(s, rhs) @@ -381,11 +384,13 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { rhs } } else { + // dropped is not empty + val wrapped = Wrap(dropped) // we must be done - Chain.fromSeq(dropped).concat(rhs) + if (rhs.isEmpty) wrapped else Append(wrapped, rhs) } case Append(l, r) => - go(count, l, r.concat(rhs)) + go(count, l, if (rhs.isEmpty) r else Append(r, rhs)) case Singleton(_) => // due to the invariant count >= 1 if (count > 1) go(count - 1, rhs, Chain.nil) @@ -422,10 +427,12 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { } } else { // we must be done - lhs.concat(Chain.fromSeq(dropped)) + // note: dropped.nonEmpty + val wrapped = Wrap(dropped) + if (lhs.isEmpty) wrapped else Append(lhs, wrapped) } case Append(l, r) => - go(lhs.concat(l), count, r) + go(if (lhs.isEmpty) l else Append(lhs, l), count, r) case Singleton(_) => // due to the invariant count >= 1 if (count > 1) go(Chain.nil, count - 1, lhs) diff --git a/tests/shared/src/test/scala/cats/tests/ChainSuite.scala b/tests/shared/src/test/scala/cats/tests/ChainSuite.scala index 7794823bfd..154ec56304 100644 --- a/tests/shared/src/test/scala/cats/tests/ChainSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/ChainSuite.scala @@ -449,25 +449,36 @@ class ChainSuite extends CatsSuite { } } + private val genChainDropTakeArgs = + Arbitrary.arbitrary[Chain[Int]].flatMap { chain => + // Bias to values close to the length + Gen + .oneOf( + Gen.choose(Int.MinValue, Int.MaxValue), + Gen.choose(-1, chain.length.toInt + 1) + ) + .map((chain, _)) + } + test("drop(cnt).toList == toList.drop(cnt)") { - forAll { (chain: Chain[Int], count: Int) => + forAll(genChainDropTakeArgs) { case (chain: Chain[Int], count: Int) => assert(chain.drop(count).toList == chain.toList.drop(count)) } } test("dropRight(cnt).toList == toList.dropRight(cnt)") { - forAll { (chain: Chain[Int], count: Int) => + forAll(genChainDropTakeArgs) { case (chain: Chain[Int], count: Int) => assert(chain.dropRight(count).toList == chain.toList.dropRight(count)) } } test("take(cnt).toList == toList.take(cnt)") { - forAll { (chain: Chain[Int], count: Int) => + forAll(genChainDropTakeArgs) { case (chain: Chain[Int], count: Int) => assert(chain.take(count).toList == chain.toList.take(count)) } } test("takeRight(cnt).toList == toList.takeRight(cnt)") { - forAll { (chain: Chain[Int], count: Int) => + forAll(genChainDropTakeArgs) { case (chain: Chain[Int], count: Int) => assert(chain.takeRight(count).toList == chain.toList.takeRight(count)) } } From a9c6f313787e1d4a3c079d06bc9f7aae61e51fdb Mon Sep 17 00:00:00 2001 From: "P. Oscar Boykin" Date: Thu, 2 Jan 2025 18:23:44 -1000 Subject: [PATCH 108/123] Optimize Chain.traverseVoid --- core/src/main/scala/cats/data/Chain.scala | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/core/src/main/scala/cats/data/Chain.scala b/core/src/main/scala/cats/data/Chain.scala index c93a1719e9..f0acbac16e 100644 --- a/core/src/main/scala/cats/data/Chain.scala +++ b/core/src/main/scala/cats/data/Chain.scala @@ -1258,11 +1258,22 @@ sealed abstract private[data] class ChainInstances extends ChainInstances1 { G match { case x: StackSafeMonad[G] => Traverse.traverseVoidDirectly(fa.iterator)(f)(x) case _ => - foldRight(fa, Eval.now(G.unit)) { (a, acc) => - G.map2Eval(f(a), acc) { (_, _) => - () + @tailrec + def go(fa: Chain[A], rhs: Chain[A], acc: G[Unit]): G[Unit] = + fa match { + case Empty => + if (rhs.isEmpty) acc + else go(rhs, Empty, acc) + case Singleton(a) => + go(rhs, Empty, G.productL(acc)(f(a))) + case Append(l, r) => + go(l, if (rhs.isEmpty) r else Append(r, rhs), acc) + case Wrap(as) => + val va = Traverse[Vector].traverseVoid(as.toVector)(f) + go(rhs, Empty, G.productL(acc)(va)) } - }.value + + go(fa, Empty, G.unit) } final override def toIterable[A](fa: Chain[A]): Iterable[A] = new scala.collection.AbstractIterable[A] { From 49625fef4932854bae0fbfe5efdb4f12d98c4968 Mon Sep 17 00:00:00 2001 From: "P. Oscar Boykin" Date: Fri, 3 Jan 2025 08:11:44 -1000 Subject: [PATCH 109/123] respond to review comments --- core/src/main/scala/cats/data/Chain.scala | 68 +++++++++++++---------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/core/src/main/scala/cats/data/Chain.scala b/core/src/main/scala/cats/data/Chain.scala index 262beaaf87..0b96e46857 100644 --- a/core/src/main/scala/cats/data/Chain.scala +++ b/core/src/main/scala/cats/data/Chain.scala @@ -259,24 +259,26 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { /** * take a certain amount of items from the front of the Chain */ - final def take(count: Int): Chain[A] = { + final def take(count: Long): Chain[A] = { // invariant count >= 1 @tailrec - def go(lhs: Chain[A], count: Int, arg: Chain[A], rhs: Chain[A]): Chain[A] = + def go(lhs: Chain[A], count: Long, arg: Chain[A], rhs: Chain[A]): Chain[A] = arg match { case Wrap(seq) => if (count == 1) { lhs.append(seq.head) } else { // count > 1 - val taken = seq.take(count) - // we may have not takeped all of count + val taken = + if (count < Int.MaxValue) seq.take(count.toInt) + else seq.take(Int.MaxValue) + // we may have not taken all of count val newCount = count - taken.length val wrapped = Wrap(taken) // this is more efficient than using concat val newLhs = if (lhs.isEmpty) wrapped else Append(lhs, wrapped) if (newCount > 0) { - // we have to keep takeping on the rhs + // we have to keep taking on the rhs go(newLhs, newCount, rhs, Chain.nil) } else { // newCount == 0, we have taken enough @@ -288,38 +290,42 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { case s @ Singleton(_) => // due to the invariant count >= 1 val newLhs = if (lhs.isEmpty) s else Append(lhs, s) - if (count > 1) { - go(newLhs, count - 1, rhs, Chain.nil) + if (count > 1L) { + go(newLhs, count - 1L, rhs, Chain.nil) } else newLhs case Empty => + // this empty check isn't an optimization but to ensure + // the recursion terminates. if (rhs.isEmpty) lhs - else go(lhs, count, rhs, Chain.nil) + else go(lhs, count, rhs, Empty) } - if (count <= 0) Empty + if (count <= 0L) Empty else go(Empty, count, this, Empty) } /** * take a certain amount of items from the back of the Chain */ - final def takeRight(count: Int): Chain[A] = { + final def takeRight(count: Long): Chain[A] = { // invariant count >= 1 @tailrec - def go(lhs: Chain[A], count: Int, arg: Chain[A], rhs: Chain[A]): Chain[A] = + def go(lhs: Chain[A], count: Long, arg: Chain[A], rhs: Chain[A]): Chain[A] = arg match { case Wrap(seq) => - if (count == 1) { + if (count == 1L) { seq.last +: rhs } else { // count > 1 - val taken = seq.takeRight(count) - // we may have not takeped all of count + val taken = + if (count < Int.MaxValue) seq.takeRight(count.toInt) + else seq.takeRight(Int.MaxValue) + // we may have not taken all of count val newCount = count - taken.length val wrapped = Wrap(taken) val newRhs = if (rhs.isEmpty) wrapped else Append(wrapped, rhs) if (newCount > 0) { - // we have to keep takeping on the rhs + // we have to keep taking on the rhs go(Chain.nil, newCount, lhs, newRhs) } else { // newCount == 0, we have taken enough @@ -335,8 +341,10 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { go(Empty, count - 1, lhs, newRhs) } else newRhs case Empty => + // this empty check isn't an optimization but to ensure + // the recursion terminates. if (lhs.isEmpty) rhs - else go(Chain.nil, count, lhs, rhs) + else go(Empty, count, lhs, rhs) } if (count <= 0) Empty @@ -365,13 +373,13 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { /** * Drop a certain amount of items from the front of the Chain */ - final def drop(count: Int): Chain[A] = { + final def drop(count: Long): Chain[A] = { // invariant count >= 1 @tailrec - def go(count: Int, arg: Chain[A], rhs: Chain[A]): Chain[A] = + def go(count: Long, arg: Chain[A], rhs: Chain[A]): Chain[A] = arg match { case Wrap(seq) => - val dropped = seq.drop(count) + val dropped = if (count < Int.MaxValue) seq.drop(count.toInt) else seq.drop(Int.MaxValue) if (dropped.isEmpty) { // we may have not dropped all of count val newCount = count - seq.length @@ -393,31 +401,33 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { go(count, l, if (rhs.isEmpty) r else Append(r, rhs)) case Singleton(_) => // due to the invariant count >= 1 - if (count > 1) go(count - 1, rhs, Chain.nil) + if (count > 1L) go(count - 1L, rhs, Chain.nil) else rhs case Empty => + // this empty check isn't an optimization but to ensure + // the recursion terminates. if (rhs.isEmpty) Empty - else go(count, rhs, Chain.nil) + else go(count, rhs, Empty) } - if (count <= 0) this + if (count <= 0L) this else go(count, this, Empty) } /** * Drop a certain amount of items from the back of the Chain */ - final def dropRight(count: Int): Chain[A] = { + final def dropRight(count: Long): Chain[A] = { // invariant count >= 1 @tailrec - def go(lhs: Chain[A], count: Int, arg: Chain[A]): Chain[A] = + def go(lhs: Chain[A], count: Long, arg: Chain[A]): Chain[A] = arg match { case Wrap(seq) => - val dropped = seq.dropRight(count) + val dropped = if (count < Int.MaxValue) seq.dropRight(count.toInt) else seq.dropRight(Int.MaxValue) if (dropped.isEmpty) { // we may have not dropped all of count val newCount = count - seq.length - if (newCount > 0) { + if (newCount > 0L) { // we have to keep dropping on the rhs go(Chain.nil, newCount, lhs) } else { @@ -435,11 +445,13 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { go(if (lhs.isEmpty) l else Append(lhs, l), count, r) case Singleton(_) => // due to the invariant count >= 1 - if (count > 1) go(Chain.nil, count - 1, lhs) + if (count > 1L) go(Chain.nil, count - 1L, lhs) else lhs case Empty => + // this empty check isn't an optimization but to ensure + // the recursion terminates. if (lhs.isEmpty) Empty - else go(Chain.nil, count, lhs) + else go(Empty, count, lhs) } if (count <= 0) this From fe40b32fa9558fbf7478355de4bad43ae7d94730 Mon Sep 17 00:00:00 2001 From: "P. Oscar Boykin" Date: Fri, 3 Jan 2025 08:28:42 -1000 Subject: [PATCH 110/123] test Chain traverse laws --- tests/shared/src/test/scala/cats/tests/TraverseSuite.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/shared/src/test/scala/cats/tests/TraverseSuite.scala b/tests/shared/src/test/scala/cats/tests/TraverseSuite.scala index 1c6e8a1ad0..6d64bfa794 100644 --- a/tests/shared/src/test/scala/cats/tests/TraverseSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/TraverseSuite.scala @@ -22,7 +22,9 @@ package cats.tests import cats._ +import cats.data.Chain import cats.kernel.compat.scalaVersionSpecific._ +import cats.laws.discipline.arbitrary._ import cats.syntax.all._ import org.scalacheck.Arbitrary import org.scalacheck.Prop._ @@ -119,6 +121,7 @@ object TraverseSuite { class TraverseListSuite extends TraverseSuite[List]("List") class TraverseVectorSuite extends TraverseSuite[Vector]("Vector") +class TraverseChainSuite extends TraverseSuite[Chain]("Chain") @annotation.nowarn("cat=deprecation") class TraverseStreamSuite extends TraverseSuite[Stream]("Stream") From 38e2c7e603895631a120b8714769abd9a3d78d4e Mon Sep 17 00:00:00 2001 From: "P. Oscar Boykin" Date: Fri, 3 Jan 2025 08:36:53 -1000 Subject: [PATCH 111/123] use NonEmpty in traverseVoid --- core/src/main/scala/cats/data/Chain.scala | 29 ++++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/core/src/main/scala/cats/data/Chain.scala b/core/src/main/scala/cats/data/Chain.scala index f0acbac16e..fcf3a3a99e 100644 --- a/core/src/main/scala/cats/data/Chain.scala +++ b/core/src/main/scala/cats/data/Chain.scala @@ -1259,21 +1259,32 @@ sealed abstract private[data] class ChainInstances extends ChainInstances1 { case x: StackSafeMonad[G] => Traverse.traverseVoidDirectly(fa.iterator)(f)(x) case _ => @tailrec - def go(fa: Chain[A], rhs: Chain[A], acc: G[Unit]): G[Unit] = + def go(fa: NonEmpty[A], rhs: Chain[A], acc: G[Unit]): G[Unit] = fa match { - case Empty => - if (rhs.isEmpty) acc - else go(rhs, Empty, acc) - case Singleton(a) => - go(rhs, Empty, G.productL(acc)(f(a))) case Append(l, r) => go(l, if (rhs.isEmpty) r else Append(r, rhs), acc) case Wrap(as) => - val va = Traverse[Vector].traverseVoid(as.toVector)(f) - go(rhs, Empty, G.productL(acc)(va)) + val va = Foldable[Seq].traverseVoid(as)(f) + val acc1 = G.productL(acc)(va) + rhs match { + case Empty => acc1 + case ne: NonEmpty[A] => + go(ne, Empty, acc1) + } + case Singleton(a) => + val acc1 = G.productL(acc)(f(a)) + rhs match { + case Empty => acc1 + case ne: NonEmpty[A] => + go(ne, Empty, acc1) + } } - go(fa, Empty, G.unit) + fa match { + case Empty => G.unit + case ne: NonEmpty[A] => + go(ne, Empty, G.unit) + } } final override def toIterable[A](fa: Chain[A]): Iterable[A] = new scala.collection.AbstractIterable[A] { From f56cad6883b6661abb5e566a73f420594fd11fd6 Mon Sep 17 00:00:00 2001 From: "P. Oscar Boykin" Date: Fri, 3 Jan 2025 08:55:31 -1000 Subject: [PATCH 112/123] recurse on NonEmpty --- core/src/main/scala/cats/data/Chain.scala | 141 +++++++++--------- .../test/scala/cats/tests/ChainSuite.scala | 8 +- 2 files changed, 77 insertions(+), 72 deletions(-) diff --git a/core/src/main/scala/cats/data/Chain.scala b/core/src/main/scala/cats/data/Chain.scala index 0b96e46857..ce4e1eb9b1 100644 --- a/core/src/main/scala/cats/data/Chain.scala +++ b/core/src/main/scala/cats/data/Chain.scala @@ -262,7 +262,7 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { final def take(count: Long): Chain[A] = { // invariant count >= 1 @tailrec - def go(lhs: Chain[A], count: Long, arg: Chain[A], rhs: Chain[A]): Chain[A] = + def go(lhs: Chain[A], count: Long, arg: NonEmpty[A], rhs: Chain[A]): Chain[A] = arg match { case Wrap(seq) => if (count == 1) { @@ -277,12 +277,12 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { val wrapped = Wrap(taken) // this is more efficient than using concat val newLhs = if (lhs.isEmpty) wrapped else Append(lhs, wrapped) - if (newCount > 0) { - // we have to keep taking on the rhs - go(newLhs, newCount, rhs, Chain.nil) - } else { - // newCount == 0, we have taken enough - newLhs + rhs match { + case rhsNE: NonEmpty[A] if newCount > 0L => + // we have to keep taking on the rhs + go(newLhs, newCount, rhsNE, Empty) + case _ => + newLhs } } case Append(l, r) => @@ -290,18 +290,18 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { case s @ Singleton(_) => // due to the invariant count >= 1 val newLhs = if (lhs.isEmpty) s else Append(lhs, s) - if (count > 1L) { - go(newLhs, count - 1L, rhs, Chain.nil) - } else newLhs - case Empty => - // this empty check isn't an optimization but to ensure - // the recursion terminates. - if (rhs.isEmpty) lhs - else go(lhs, count, rhs, Empty) + rhs match { + case rhsNE: NonEmpty[A] if count > 1L => + go(newLhs, count - 1L, rhsNE, Empty) + case _ => newLhs + } } - if (count <= 0L) Empty - else go(Empty, count, this, Empty) + this match { + case ne: NonEmpty[A] if count > 0L => + go(Empty, count, ne, Empty) + case _ => Empty + } } /** @@ -310,7 +310,7 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { final def takeRight(count: Long): Chain[A] = { // invariant count >= 1 @tailrec - def go(lhs: Chain[A], count: Long, arg: Chain[A], rhs: Chain[A]): Chain[A] = + def go(lhs: Chain[A], count: Long, arg: NonEmpty[A], rhs: Chain[A]): Chain[A] = arg match { case Wrap(seq) => if (count == 1L) { @@ -324,12 +324,10 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { val newCount = count - taken.length val wrapped = Wrap(taken) val newRhs = if (rhs.isEmpty) wrapped else Append(wrapped, rhs) - if (newCount > 0) { - // we have to keep taking on the rhs - go(Chain.nil, newCount, lhs, newRhs) - } else { - // newCount == 0, we have taken enough - newRhs + lhs match { + case lhsNE: NonEmpty[A] if newCount > 0 => + go(Empty, newCount, lhsNE, newRhs) + case _ => newRhs } } case Append(l, r) => @@ -337,18 +335,18 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { case s @ Singleton(_) => // due to the invariant count >= 1 val newRhs = if (rhs.isEmpty) s else Append(s, rhs) - if (count > 1) { - go(Empty, count - 1, lhs, newRhs) - } else newRhs - case Empty => - // this empty check isn't an optimization but to ensure - // the recursion terminates. - if (lhs.isEmpty) rhs - else go(Empty, count, lhs, rhs) + lhs match { + case lhsNE: NonEmpty[A] if count > 1 => + go(Empty, count - 1, lhsNE, newRhs) + case _ => newRhs + } } - if (count <= 0) Empty - else go(Empty, count, this, Empty) + this match { + case ne: NonEmpty[A] if count > 0L => + go(Empty, count, ne, Empty) + case _ => Empty + } } /** @@ -376,20 +374,21 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { final def drop(count: Long): Chain[A] = { // invariant count >= 1 @tailrec - def go(count: Long, arg: Chain[A], rhs: Chain[A]): Chain[A] = + def go(count: Long, arg: NonEmpty[A], rhs: Chain[A]): Chain[A] = arg match { case Wrap(seq) => val dropped = if (count < Int.MaxValue) seq.drop(count.toInt) else seq.drop(Int.MaxValue) if (dropped.isEmpty) { // we may have not dropped all of count val newCount = count - seq.length - if (newCount > 0) { - // we have to keep dropping on the rhs - go(newCount, rhs, Chain.nil) - } else { - // we know that count >= seq.length else we wouldn't be empty - // so in this case, it is exactly count == seq.length - rhs + rhs match { + case rhsNE: NonEmpty[A] if newCount > 0 => + // we have to keep dropping on the rhs + go(newCount, rhsNE, Empty) + case _ => + // we know that count >= seq.length else we wouldn't be empty + // so in this case, it is exactly count == seq.length + rhs } } else { // dropped is not empty @@ -401,17 +400,19 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { go(count, l, if (rhs.isEmpty) r else Append(r, rhs)) case Singleton(_) => // due to the invariant count >= 1 - if (count > 1L) go(count - 1L, rhs, Chain.nil) - else rhs - case Empty => - // this empty check isn't an optimization but to ensure - // the recursion terminates. - if (rhs.isEmpty) Empty - else go(count, rhs, Empty) + rhs match { + case rhsNE: NonEmpty[A] if count > 1L => + go(count - 1L, rhsNE, Empty) + case _ => + rhs + } } - if (count <= 0L) this - else go(count, this, Empty) + this match { + case ne: NonEmpty[A] if count > 0L => + go(count, ne, Empty) + case _ => this + } } /** @@ -420,20 +421,21 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { final def dropRight(count: Long): Chain[A] = { // invariant count >= 1 @tailrec - def go(lhs: Chain[A], count: Long, arg: Chain[A]): Chain[A] = + def go(lhs: Chain[A], count: Long, arg: NonEmpty[A]): Chain[A] = arg match { case Wrap(seq) => val dropped = if (count < Int.MaxValue) seq.dropRight(count.toInt) else seq.dropRight(Int.MaxValue) if (dropped.isEmpty) { // we may have not dropped all of count val newCount = count - seq.length - if (newCount > 0L) { - // we have to keep dropping on the rhs - go(Chain.nil, newCount, lhs) - } else { - // we know that count >= seq.length else we wouldn't be empty - // so in this case, it is exactly count == seq.length - lhs + lhs match { + case lhsNE: NonEmpty[A] if newCount > 0L => + // we have to keep dropping on the lhs + go(Empty, newCount, lhsNE) + case _ => + // we know that count >= seq.length else we wouldn't be empty + // so in this case, it is exactly count == seq.length + lhs } } else { // we must be done @@ -445,17 +447,20 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { go(if (lhs.isEmpty) l else Append(lhs, l), count, r) case Singleton(_) => // due to the invariant count >= 1 - if (count > 1L) go(Chain.nil, count - 1L, lhs) - else lhs - case Empty => - // this empty check isn't an optimization but to ensure - // the recursion terminates. - if (lhs.isEmpty) Empty - else go(Empty, count, lhs) + lhs match { + case lhsNE: NonEmpty[A] if count > 1L => + go(Empty, count - 1L, lhsNE) + case _ => + lhs + } } - if (count <= 0) this - else go(Empty, count, this) + this match { + case ne: NonEmpty[A] if count > 0L => + go(Empty, count, ne) + case _ => + this + } } /** diff --git a/tests/shared/src/test/scala/cats/tests/ChainSuite.scala b/tests/shared/src/test/scala/cats/tests/ChainSuite.scala index 154ec56304..b25e2022e3 100644 --- a/tests/shared/src/test/scala/cats/tests/ChainSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/ChainSuite.scala @@ -462,24 +462,24 @@ class ChainSuite extends CatsSuite { test("drop(cnt).toList == toList.drop(cnt)") { forAll(genChainDropTakeArgs) { case (chain: Chain[Int], count: Int) => - assert(chain.drop(count).toList == chain.toList.drop(count)) + assertEquals(chain.drop(count).toList, chain.toList.drop(count)) } } test("dropRight(cnt).toList == toList.dropRight(cnt)") { forAll(genChainDropTakeArgs) { case (chain: Chain[Int], count: Int) => - assert(chain.dropRight(count).toList == chain.toList.dropRight(count)) + assertEquals(chain.dropRight(count).toList, chain.toList.dropRight(count)) } } test("take(cnt).toList == toList.take(cnt)") { forAll(genChainDropTakeArgs) { case (chain: Chain[Int], count: Int) => - assert(chain.take(count).toList == chain.toList.take(count)) + assertEquals(chain.take(count).toList, chain.toList.take(count)) } } test("takeRight(cnt).toList == toList.takeRight(cnt)") { forAll(genChainDropTakeArgs) { case (chain: Chain[Int], count: Int) => - assert(chain.takeRight(count).toList == chain.toList.takeRight(count)) + assertEquals(chain.takeRight(count).toList, chain.toList.takeRight(count)) } } } From 2fb2f61095ee2639bedba215a09a5a4105846629 Mon Sep 17 00:00:00 2001 From: "P. Oscar Boykin" Date: Fri, 3 Jan 2025 09:54:04 -1000 Subject: [PATCH 113/123] fix build on 2.12 --- core/src/main/scala/cats/data/Chain.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/cats/data/Chain.scala b/core/src/main/scala/cats/data/Chain.scala index fcf3a3a99e..a09e155e3f 100644 --- a/core/src/main/scala/cats/data/Chain.scala +++ b/core/src/main/scala/cats/data/Chain.scala @@ -1264,7 +1264,7 @@ sealed abstract private[data] class ChainInstances extends ChainInstances1 { case Append(l, r) => go(l, if (rhs.isEmpty) r else Append(r, rhs), acc) case Wrap(as) => - val va = Foldable[Seq].traverseVoid(as)(f) + val va = Foldable[collection.immutable.Seq].traverseVoid(as)(f) val acc1 = G.productL(acc)(va) rhs match { case Empty => acc1 From 480488f45c7aee05843ab4f43e9ba8c95a0fe8d9 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Tue, 7 Jan 2025 12:08:17 +0000 Subject: [PATCH 114/123] Update munit to 1.0.4 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 8779410704..5793f66fde 100644 --- a/build.sbt +++ b/build.sbt @@ -6,7 +6,7 @@ val disciplineVersion = "1.7.0" val disciplineMunitVersion = "2.0.0" -val munitVersion = "1.0.3" +val munitVersion = "1.0.4" val PrimaryJava = JavaSpec.temurin("8") val LTSJava = JavaSpec.temurin("17") From 4dddf8c2f87c874d45251c5557fa2cea80f6a9ee Mon Sep 17 00:00:00 2001 From: "P. Oscar Boykin" Date: Thu, 9 Jan 2025 10:22:58 -1000 Subject: [PATCH 115/123] maintain Wrap invariant --- core/src/main/scala/cats/data/Chain.scala | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/core/src/main/scala/cats/data/Chain.scala b/core/src/main/scala/cats/data/Chain.scala index ce4e1eb9b1..11f8a51ca8 100644 --- a/core/src/main/scala/cats/data/Chain.scala +++ b/core/src/main/scala/cats/data/Chain.scala @@ -378,7 +378,9 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { arg match { case Wrap(seq) => val dropped = if (count < Int.MaxValue) seq.drop(count.toInt) else seq.drop(Int.MaxValue) - if (dropped.isEmpty) { + val lc = dropped.lengthCompare(1) + if (lc < 0) { + // if dropped.length < 1, then it is zero // we may have not dropped all of count val newCount = count - seq.length rhs match { @@ -392,7 +394,7 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { } } else { // dropped is not empty - val wrapped = Wrap(dropped) + val wrapped = if (lc > 0) Wrap(dropped) else Singleton(dropped.head) // we must be done if (rhs.isEmpty) wrapped else Append(wrapped, rhs) } @@ -425,7 +427,9 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { arg match { case Wrap(seq) => val dropped = if (count < Int.MaxValue) seq.dropRight(count.toInt) else seq.dropRight(Int.MaxValue) - if (dropped.isEmpty) { + val lc = dropped.lengthCompare(1) + if (lc < 0) { + // if dropped.length < 1, then it is zero // we may have not dropped all of count val newCount = count - seq.length lhs match { @@ -440,7 +444,7 @@ sealed abstract class Chain[+A] extends ChainCompat[A] { } else { // we must be done // note: dropped.nonEmpty - val wrapped = Wrap(dropped) + val wrapped = if (lc > 0) Wrap(dropped) else Singleton(dropped.head) if (lhs.isEmpty) wrapped else Append(lhs, wrapped) } case Append(l, r) => @@ -1128,7 +1132,8 @@ object Chain extends ChainInstances with ChainCompanionCompat { * if the length is one, fromSeq returns Singleton * * The only places we create Wrap is in fromSeq and in methods that preserve - * length: zipWithIndex, map, sort + * length: zipWithIndex, map, sort. Additionally, in drop/dropRight we carefully + * preserve this invariant. */ final private[data] case class Wrap[A](seq: immutable.Seq[A]) extends NonEmpty[A] From 71e076b2eb140d10fa2b77691fdf48a717a58922 Mon Sep 17 00:00:00 2001 From: "P. Oscar Boykin" Date: Thu, 9 Jan 2025 11:13:45 -1000 Subject: [PATCH 116/123] slightly optimize Chain.fromSeq --- .../cats/data/ChainCompanionCompat.scala | 14 ++++++++------ .../cats/data/ChainCompanionCompat.scala | 10 ++++++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/core/src/main/scala-2.12/cats/data/ChainCompanionCompat.scala b/core/src/main/scala-2.12/cats/data/ChainCompanionCompat.scala index d113e733f3..c35c704ccd 100644 --- a/core/src/main/scala-2.12/cats/data/ChainCompanionCompat.scala +++ b/core/src/main/scala-2.12/cats/data/ChainCompanionCompat.scala @@ -38,15 +38,17 @@ private[data] trait ChainCompanionCompat { } private def fromImmutableSeq[A](s: immutable.Seq[A]): Chain[A] = { - if (s.isEmpty) nil - else if (s.lengthCompare(1) == 0) one(s.head) - else Wrap(s) + val lc = s.lengthCompare(1) + if (lc < 0) nil + else if (lc > 0) Wrap(s.toVector) + else one(s.head) } private def fromMutableSeq[A](s: Seq[A]): Chain[A] = { - if (s.isEmpty) nil - else if (s.lengthCompare(1) == 0) one(s.head) - else Wrap(s.toVector) + val lc = s.lengthCompare(1) + if (lc < 0) nil + else if (lc > 0) Wrap(s.toVector) + else one(s.head) } /** diff --git a/core/src/main/scala-2.13+/cats/data/ChainCompanionCompat.scala b/core/src/main/scala-2.13+/cats/data/ChainCompanionCompat.scala index 1a8be19c79..3821a1ce8c 100644 --- a/core/src/main/scala-2.13+/cats/data/ChainCompanionCompat.scala +++ b/core/src/main/scala-2.13+/cats/data/ChainCompanionCompat.scala @@ -28,10 +28,12 @@ private[data] trait ChainCompanionCompat { /** * Creates a Chain from the specified sequence. */ - def fromSeq[A](s: Seq[A]): Chain[A] = - if (s.isEmpty) nil - else if (s.lengthCompare(1) == 0) one(s.head) - else Wrap(s) + def fromSeq[A](s: Seq[A]): Chain[A] = { + val lc = s.lengthCompare(1) + if (lc < 0) nil + else if (lc > 0) Wrap(s) + else one(s.head) + } /** * Creates a Chain from the specified IterableOnce. From fdcff72d177ad169ca44a18b5f1965b4b645dac4 Mon Sep 17 00:00:00 2001 From: "P. Oscar Boykin" Date: Fri, 10 Jan 2025 14:46:50 -1000 Subject: [PATCH 117/123] don't convert immutable to Vector --- core/src/main/scala-2.12/cats/data/ChainCompanionCompat.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala-2.12/cats/data/ChainCompanionCompat.scala b/core/src/main/scala-2.12/cats/data/ChainCompanionCompat.scala index c35c704ccd..de7cd35d22 100644 --- a/core/src/main/scala-2.12/cats/data/ChainCompanionCompat.scala +++ b/core/src/main/scala-2.12/cats/data/ChainCompanionCompat.scala @@ -40,7 +40,7 @@ private[data] trait ChainCompanionCompat { private def fromImmutableSeq[A](s: immutable.Seq[A]): Chain[A] = { val lc = s.lengthCompare(1) if (lc < 0) nil - else if (lc > 0) Wrap(s.toVector) + else if (lc > 0) Wrap(s) else one(s.head) } From 1b749b14d1ca03c64aa97488a97d480a75c466b1 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 04:06:37 +0000 Subject: [PATCH 118/123] Update scalafmt-core to 3.8.4 --- .scalafmt.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index a530097004..4490c6fcb2 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version=3.8.2 +version=3.8.4 align.openParenCallSite = true align.openParenDefnSite = true maxColumn = 120 From 42490f49d2a62289c8ca0a57357f323982eeb93b Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 04:06:56 +0000 Subject: [PATCH 119/123] Reformat with scalafmt 3.8.4 Executed command: scalafmt --non-interactive --- core/src/main/scala/cats/evidence/As.scala | 28 +++++++++---------- .../src/test/scala/cats/tests/AsSuite.scala | 14 +++++----- .../scala/cats/tests/IndexedStateTSuite.scala | 10 ++++--- .../test/scala/cats/tests/NestedSuite.scala | 5 ++-- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/core/src/main/scala/cats/evidence/As.scala b/core/src/main/scala/cats/evidence/As.scala index 7d6b800d13..4fe4800afd 100644 --- a/core/src/main/scala/cats/evidence/As.scala +++ b/core/src/main/scala/cats/evidence/As.scala @@ -50,9 +50,9 @@ sealed abstract class As[-A, +B] extends Serializable { */ def substitute[F[-_]](p: F[B]): F[A] - @inline final def andThen[C](that: (B As C)): (A As C) = As.compose(that, this) + @inline final def andThen[C](that: B As C): A As C = As.compose(that, this) - @inline final def compose[C](that: (C As A)): (C As B) = As.compose(this, that) + @inline final def compose[C](that: C As A): C As B = As.compose(this, that) @inline final def coerce(a: A): B = As.witness(this)(a) @@ -73,9 +73,9 @@ sealed abstract class AsInstances { * Subtyping forms a category */ implicit val liskov: Category[As] = new Category[As] { - def id[A]: (A As A) = refl[A] + def id[A]: A As A = refl[A] - def compose[A, B, C](bc: B As C, ab: A As B): (A As C) = bc.compose(ab) + def compose[A, B, C](bc: B As C, ab: A As B): A As C = bc.compose(ab) } } @@ -92,7 +92,7 @@ object As extends AsInstances with AsSupport { /** * Subtyping is reflexive */ - implicit def refl[A]: (A As A) = + implicit def refl[A]: A As A = reflAny.asInstanceOf[A As A] /** @@ -114,7 +114,7 @@ object As extends AsInstances with AsSupport { /** * reify a subtype relationship as a Liskov relationship */ - @inline def reify[A, B >: A]: (A As B) = refl + @inline def reify[A, B >: A]: A As B = refl /** * It can be convenient to convert a <:< value into a `<~<` value. @@ -127,7 +127,7 @@ object As extends AsInstances with AsSupport { /** * We can lift subtyping into any covariant type constructor */ - def co[T[+_], A, A2](a: A As A2): (T[A] As T[A2]) = { + def co[T[+_], A, A2](a: A As A2): T[A] As T[A2] = { type L[-α] = T[α] As T[A2] a.substitute[L](refl) } @@ -179,7 +179,7 @@ object As extends AsInstances with AsSupport { def lift2[T[+_, +_], A, A2, B, B2]( a: A As A2, b: B As B2 - ): (T[A, B] As T[A2, B2]) = { + ): T[A, B] As T[A2, B2] = { type a[-X] = T[X, B2] As T[A2, B2] type b[-X] = T[A, X] As T[A2, B2] b.substitute[b](a.substitute[a](refl)) @@ -192,7 +192,7 @@ object As extends AsInstances with AsSupport { * Given that F has the shape: F[-_], we show that: * (A As B) implies (F[B] As F[A]) */ - def contra[T[-_], A, B](a: A As B): (T[B] As T[A]) = { + def contra[T[-_], A, B](a: A As B): T[B] As T[A] = { type L[-α] = T[B] As T[α] a.substitute[L](refl) } @@ -201,27 +201,27 @@ object As extends AsInstances with AsSupport { // parameter. Here we provide the proof for what we expect to be the // most common shapes. - def contra1_2[T[-_, _], Z, A, B](a: A As Z): (T[Z, B] As T[A, B]) = { + def contra1_2[T[-_, _], Z, A, B](a: A As Z): T[Z, B] As T[A, B] = { type L[-α] = T[Z, B] As T[α, B] a.substitute[L](refl) } - def contra2_2[T[_, -_], Z, A, B](a: B As Z): (T[A, Z] As T[A, B]) = { + def contra2_2[T[_, -_], Z, A, B](a: B As Z): T[A, Z] As T[A, B] = { type L[-α] = T[A, Z] As T[A, α] a.substitute[L](refl) } - def contra1_3[T[-_, _, _], Z, A, B, C](a: A As Z): (T[Z, B, C] As T[A, B, C]) = { + def contra1_3[T[-_, _, _], Z, A, B, C](a: A As Z): T[Z, B, C] As T[A, B, C] = { type L[-α] = T[Z, B, C] As T[α, B, C] a.substitute[L](refl) } - def contra2_3[T[_, -_, _], Z, A, B, C](a: B As Z): (T[A, Z, C] As T[A, B, C]) = { + def contra2_3[T[_, -_, _], Z, A, B, C](a: B As Z): T[A, Z, C] As T[A, B, C] = { type L[-α] = T[A, Z, C] As T[A, α, C] a.substitute[L](refl) } - def contra3_3[T[_, _, -_], Z, A, B, C](a: C As Z): (T[A, B, Z] As T[A, B, C]) = { + def contra3_3[T[_, _, -_], Z, A, B, C](a: C As Z): T[A, B, Z] As T[A, B, C] = { type L[-α] = T[A, B, Z] As T[A, B, α] a.substitute[L](refl) } diff --git a/tests/shared/src/test/scala/cats/tests/AsSuite.scala b/tests/shared/src/test/scala/cats/tests/AsSuite.scala index 559e2f9745..533f6242fe 100644 --- a/tests/shared/src/test/scala/cats/tests/AsSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/AsSuite.scala @@ -103,12 +103,12 @@ class AsSuite extends CatsSuite { test("we can lift subtyping to covariant type constructors") { val cAsA: Bottom As Top = implicitly val co: List[Bottom] As List[Top] = As.co(cAsA) - val co2: ((Bottom, String) As (Top, String)) = As.co2(cAsA) - val co2_2: ((String, Bottom) As (String, Top)) = As.co2_2(cAsA) - val co3: ((Bottom, Unit, Unit) As (Top, Unit, Unit)) = As.co3(cAsA) - val co3_2: ((Unit, Bottom, Unit) As (Unit, Top, Unit)) = As.co3_2(cAsA) - val co3_3: ((Unit, Unit, Bottom) As (Unit, Unit, Top)) = As.co3_3(cAsA) - val lift2: ((Bottom, String) As (Top, Any)) = As.lift2(cAsA, implicitly) + val co2: (Bottom, String) As (Top, String) = As.co2(cAsA) + val co2_2: (String, Bottom) As (String, Top) = As.co2_2(cAsA) + val co3: (Bottom, Unit, Unit) As (Top, Unit, Unit) = As.co3(cAsA) + val co3_2: (Unit, Bottom, Unit) As (Unit, Top, Unit) = As.co3_2(cAsA) + val co3_3: (Unit, Unit, Bottom) As (Unit, Unit, Top) = As.co3_3(cAsA) + val lift2: (Bottom, String) As (Top, Any) = As.lift2(cAsA, implicitly) } test("we can lift subtyping to contravariant type constructors") { @@ -119,7 +119,7 @@ class AsSuite extends CatsSuite { type EatF23[B, -A, C] = A => (B, C) type EatF33[B, C, -A] = A => (B, C) - val cAsA: (Bottom As Top) = implicitly + val cAsA: Bottom As Top = implicitly val contra: Eat[Top] As Eat[Bottom] = As.contra(cAsA) val contra1_2: EatF[Top, Unit] As EatF[Bottom, Unit] = As.contra1_2(cAsA) val contra2_2: Eatꟻ[Unit, Top] As Eatꟻ[Unit, Bottom] = As.contra2_2(cAsA) diff --git a/tests/shared/src/test/scala/cats/tests/IndexedStateTSuite.scala b/tests/shared/src/test/scala/cats/tests/IndexedStateTSuite.scala index 839b38eabf..04d525c059 100644 --- a/tests/shared/src/test/scala/cats/tests/IndexedStateTSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/IndexedStateTSuite.scala @@ -412,8 +412,9 @@ class IndexedStateTSuite extends CatsSuite { checkAll("IndexedStateT[ListWrapper, MiniInt, Int, *]", FunctorFilterTests[IndexedStateT[ListWrapper, MiniInt, Int, *]].functorFilter[Int, Int, Int] ) - checkAll("FunctorFilter[IndexedStateT[ListWrapper, MiniInt, Int, *]]", - SerializableTests.serializable(FunctorFilter[IndexedStateT[ListWrapper, MiniInt, Int, *]]) + checkAll( + "FunctorFilter[IndexedStateT[ListWrapper, MiniInt, Int, *]]", + SerializableTests.serializable(FunctorFilter[IndexedStateT[ListWrapper, MiniInt, Int, *]]) ) FunctorFilter[IndexedStateT[ListWrapper, String, Int, *]] @@ -438,8 +439,9 @@ class IndexedStateTSuite extends CatsSuite { implicit val F: Monad[ListWrapper] = ListWrapper.monad implicit val FS: Bifunctor[IndexedStateT[ListWrapper, Int, *, *]] = IndexedStateT.catsDataBifunctorForIndexedStateT - checkAll("IndexedStateT[ListWrapper, MiniInt, String, Int]", - BifunctorTests[IndexedStateT[ListWrapper, MiniInt, *, *]].bifunctor[String, String, String, Int, Int, Int] + checkAll( + "IndexedStateT[ListWrapper, MiniInt, String, Int]", + BifunctorTests[IndexedStateT[ListWrapper, MiniInt, *, *]].bifunctor[String, String, String, Int, Int, Int] ) checkAll("Bifunctor[IndexedStateT[ListWrapper, Int, *, *]]", SerializableTests.serializable(Bifunctor[IndexedStateT[ListWrapper, Int, *, *]]) diff --git a/tests/shared/src/test/scala/cats/tests/NestedSuite.scala b/tests/shared/src/test/scala/cats/tests/NestedSuite.scala index 1325d874c2..3459b1f479 100644 --- a/tests/shared/src/test/scala/cats/tests/NestedSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/NestedSuite.scala @@ -240,8 +240,9 @@ class NestedSuite extends CatsSuite { checkAll("Nested[NonEmptyList, OneAnd[ListWrapper, *], *]", ReducibleTests[Nested[NonEmptyList, OneAnd[ListWrapper, *], *]].reducible[Option, Int, Int] ) - checkAll("Reducible[Nested[NonEmptyList, OneAnd[ListWrapper, *], *]]", - SerializableTests.serializable(Reducible[Nested[NonEmptyList, OneAnd[ListWrapper, *], *]]) + checkAll( + "Reducible[Nested[NonEmptyList, OneAnd[ListWrapper, *], *]]", + SerializableTests.serializable(Reducible[Nested[NonEmptyList, OneAnd[ListWrapper, *], *]]) ) } From 9ff347818b17307289b92bcc8a43caa127776111 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Mon, 13 Jan 2025 04:06:56 +0000 Subject: [PATCH 120/123] Add 'Reformat with scalafmt 3.8.4' to .git-blame-ignore-revs --- .git-blame-ignore-revs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 48c64b178a..f5fcfbfda2 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -15,3 +15,6 @@ f025b0198d55d7f5c09ee976eec9e274d8dd0309 # Scala Steward: Reformat with scalafmt 3.5.9 b4d207e9fa9f1463f0827fe20101e7901fecf820 + +# Scala Steward: Reformat with scalafmt 3.8.4 +42490f49d2a62289c8ca0a57357f323982eeb93b From cdc78fa0e423c938e09b24ab93eafbc580817d8a Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Thu, 16 Jan 2025 00:21:09 +0000 Subject: [PATCH 121/123] Update scala-library, scala-reflect to 2.13.16 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 5793f66fde..3d7293d477 100644 --- a/build.sbt +++ b/build.sbt @@ -15,7 +15,7 @@ val GraalVM = JavaSpec.graalvm("21") ThisBuild / githubWorkflowJavaVersions := Seq(PrimaryJava, LTSJava, GraalVM) val Scala212 = "2.12.20" -val Scala213 = "2.13.15" +val Scala213 = "2.13.16" val Scala3 = "3.3.4" ThisBuild / crossScalaVersions := Seq(Scala212, Scala213, Scala3) From c22061c5407f50e91fc878705e225f52ea566c15 Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 00:19:11 +0000 Subject: [PATCH 122/123] Update scalafmt-core to 3.8.5 --- .scalafmt.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index 4490c6fcb2..479f53f35f 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version=3.8.4 +version=3.8.5 align.openParenCallSite = true align.openParenDefnSite = true maxColumn = 120 From f76a0055ee99ccc32783f0388e69a1454fae6f0b Mon Sep 17 00:00:00 2001 From: "typelevel-steward[bot]" <106827141+typelevel-steward[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2025 00:20:17 +0000 Subject: [PATCH 123/123] Update sbt-typelevel, sbt-typelevel-site to 0.7.6 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index a78d755e67..9cd55b649e 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,4 @@ -val sbtTypelevelVersion = "0.7.5" +val sbtTypelevelVersion = "0.7.6" addSbtPlugin("org.typelevel" % "sbt-typelevel" % sbtTypelevelVersion) addSbtPlugin("org.typelevel" % "sbt-typelevel-site" % sbtTypelevelVersion) addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7")