Skip to content

Commit 6daf274

Browse files
authored
Merge pull request #4458 from joroKr21/const
Fix ambiguous `Const` instances and add missing instances
2 parents 65a3c5b + 4999f04 commit 6daf274

File tree

2 files changed

+89
-31
lines changed

2 files changed

+89
-31
lines changed

core/src/main/scala/cats/data/Const.scala

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ package data
2424

2525
import cats.kernel.{CommutativeMonoid, CommutativeSemigroup, LowerBounded, UpperBounded}
2626

27+
import scala.annotation.nowarn
28+
2729
/**
2830
* [[Const]] is a phantom type, it does not contain a value of its second type parameter `B`
2931
* [[Const]] can be seen as a type level version of `Function.const[A, B]: A => B => A`
@@ -39,6 +41,7 @@ final case class Const[A, B](getConst: A) {
3941
def combine(that: Const[A, B])(implicit A: Semigroup[A]): Const[A, B] =
4042
Const(A.combine(getConst, that.getConst))
4143

44+
@nowarn("cat=unused")
4245
def traverse[F[_], C](f: B => F[C])(implicit F: Applicative[F]): F[Const[A, C]] =
4346
F.pure(retag[C])
4447

@@ -51,6 +54,9 @@ final case class Const[A, B](getConst: A) {
5154
def compare(that: Const[A, B])(implicit A: Order[A]): Int =
5255
A.compare(getConst, that.getConst)
5356

57+
def hash(implicit A: Hash[A]): Int =
58+
Const(A.hash(getConst)).hashCode()
59+
5460
def show(implicit A: Show[A]): String =
5561
s"Const(${A.show(getConst)})"
5662
}
@@ -92,17 +98,19 @@ sealed abstract private[data] class ConstInstances extends ConstInstances0 {
9298

9399
implicit def catsDataOrderForConst[A: Order, B]: Order[Const[A, B]] = _ compare _
94100

101+
implicit def catsDataPartialOrderForConst[A: PartialOrder, B]: PartialOrder[Const[A, B]] = _ partialCompare _
102+
95103
implicit def catsDataAlignForConst[A: Semigroup]: Align[Const[A, *]] =
96104
new Align[Const[A, *]] {
97105
def align[B, C](fa: Const[A, B], fb: Const[A, C]): Const[A, Ior[B, C]] =
98106
Const(Semigroup[A].combine(fa.getConst, fb.getConst))
99-
def functor: Functor[Const[A, *]] = catsDataFunctorForConst
107+
def functor: Functor[Const[A, *]] = catsDataTraverseForConst
100108
}
101109

102110
implicit def catsDataShowForConst[A: Show, B]: Show[Const[A, B]] = _.show
103111

104112
implicit def catsDataTraverseForConst[C]: Traverse[Const[C, *]] =
105-
new Traverse[Const[C, *]] {
113+
new Traverse[Const[C, *]] with ConstFunctor[C] {
106114
def foldLeft[A, B](fa: Const[C, A], b: B)(f: (B, A) => B): B = b
107115

108116
def foldRight[A, B](fa: Const[C, A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = lb
@@ -121,22 +129,22 @@ sealed abstract private[data] class ConstInstances extends ConstInstances0 {
121129
implicit def catsDataTraverseFilterForConst[C]: TraverseFilter[Const[C, *]] =
122130
new TraverseFilter[Const[C, *]] {
123131

124-
override def mapFilter[A, B](fa: Const[C, A])(f: (A) => Option[B]): Const[C, B] = fa.retag
132+
override def mapFilter[A, B](fa: Const[C, A])(f: A => Option[B]): Const[C, B] = fa.retag
125133

126134
override def collect[A, B](fa: Const[C, A])(f: PartialFunction[A, B]): Const[C, B] = fa.retag
127135

128136
override def flattenOption[A](fa: Const[C, Option[A]]): Const[C, A] = fa.retag
129137

130-
override def filter[A](fa: Const[C, A])(f: (A) => Boolean): Const[C, A] = fa.retag
138+
override def filter[A](fa: Const[C, A])(f: A => Boolean): Const[C, A] = fa.retag
131139

132140
override def filterNot[A](fa: Const[C, A])(f: A => Boolean): Const[C, A] = fa.retag
133141

134142
def traverseFilter[G[_], A, B](
135143
fa: Const[C, A]
136-
)(f: (A) => G[Option[B]])(implicit G: Applicative[G]): G[Const[C, B]] =
144+
)(f: A => G[Option[B]])(implicit G: Applicative[G]): G[Const[C, B]] =
137145
G.pure(fa.retag[B])
138146

139-
override def filterA[G[_], A](fa: Const[C, A])(f: (A) => G[Boolean])(implicit G: Applicative[G]): G[Const[C, A]] =
147+
override def filterA[G[_], A](fa: Const[C, A])(f: A => G[Boolean])(implicit G: Applicative[G]): G[Const[C, A]] =
140148
G.pure(fa)
141149

142150
val traverse: Traverse[Const[C, *]] = Const.catsDataTraverseForConst[C]
@@ -151,6 +159,8 @@ sealed abstract private[data] class ConstInstances extends ConstInstances0 {
151159
x.combine(y)
152160
}
153161

162+
implicit def catsDataSemigroupForConst[A: Semigroup, B]: Semigroup[Const[A, B]] = _ combine _
163+
154164
implicit val catsDataBifoldableForConst: Bifoldable[Const] =
155165
new Bifoldable[Const] {
156166
def bifoldLeft[A, B, C](fab: Const[A, B], c: C)(f: (C, A) => C, g: (C, B) => C): C =
@@ -161,10 +171,26 @@ sealed abstract private[data] class ConstInstances extends ConstInstances0 {
161171
): Eval[C] =
162172
f(fab.getConst, c)
163173
}
174+
175+
implicit def catsDataMonoidKForConst[C: Monoid]: MonoidK[Const[C, *]] = new MonoidK[Const[C, *]] {
176+
override def empty[A]: Const[C, A] = Const.empty
177+
override def combineK[A](x: Const[C, A], y: Const[C, A]): Const[C, A] = x.combine(y)
178+
}
179+
180+
implicit def catsDataSemigroupKForConst[C: Semigroup]: SemigroupK[Const[C, *]] = new SemigroupK[Const[C, *]] {
181+
override def combineK[A](x: Const[C, A], y: Const[C, A]): Const[C, A] = x.combine(y)
182+
}
164183
}
165184

166185
sealed abstract private[data] class ConstInstances0 extends ConstInstances1 {
167186

187+
implicit def catsDataEqForConst[A: Eq, B]: Eq[Const[A, B]] = _ === _
188+
189+
implicit def catsDataHashForConst[A: Hash, B]: Hash[Const[A, B]] = new Hash[Const[A, B]] {
190+
override def hash(x: Const[A, B]): Int = x.hash
191+
override def eqv(x: Const[A, B], y: Const[A, B]): Boolean = x === y
192+
}
193+
168194
implicit def catsDataContravariantMonoidalForConst[D: Monoid]: ContravariantMonoidal[Const[D, *]] =
169195
new ContravariantMonoidal[Const[D, *]] {
170196
override def unit = Const.empty[D, Unit]
@@ -174,46 +200,51 @@ sealed abstract private[data] class ConstInstances0 extends ConstInstances1 {
174200
fa.retag[(A, B)].combine(fb.retag[(A, B)])
175201
}
176202

177-
implicit def catsDataCommutativeApplicativeForConst[C](implicit
178-
C: CommutativeMonoid[C]
179-
): CommutativeApplicative[Const[C, *]] =
180-
new ConstApplicative[C] with CommutativeApplicative[Const[C, *]] { val C0: CommutativeMonoid[C] = C }
203+
implicit def catsDataContravariantSemigroupalForConst[D: Semigroup]: ContravariantSemigroupal[Const[D, *]] =
204+
new ContravariantSemigroupal[Const[D, *]] {
205+
override def contramap[A, B](fa: Const[D, A])(f: B => A): Const[D, B] =
206+
fa.retag[B]
207+
override def product[A, B](fa: Const[D, A], fb: Const[D, B]): Const[D, (A, B)] =
208+
fa.retag[(A, B)].combine(fb.retag[(A, B)])
209+
}
181210
}
182211

183212
sealed abstract private[data] class ConstInstances1 extends ConstInstances2 {
184213

214+
implicit def catsDataCommutativeApplicativeForConst[C](implicit
215+
C: CommutativeMonoid[C]
216+
): CommutativeApplicative[Const[C, *]] =
217+
new ConstApplicative[C] with CommutativeApplicative[Const[C, *]] {
218+
val C0: CommutativeMonoid[C] = C
219+
}
220+
185221
implicit def catsDataCommutativeApplyForConst[C](implicit C: CommutativeSemigroup[C]): CommutativeApply[Const[C, *]] =
186222
new ConstApply[C] with CommutativeApply[Const[C, *]] { val C0: CommutativeSemigroup[C] = C }
187223
}
188224

189225
sealed abstract private[data] class ConstInstances2 extends ConstInstances3 {
190226

191-
implicit def catsDataSemigroupForConst[A: Semigroup, B]: Semigroup[Const[A, B]] = _ combine _
192-
193-
implicit def catsDataPartialOrderForConst[A: PartialOrder, B]: PartialOrder[Const[A, B]] = _ partialCompare _
194-
195227
implicit def catsDataApplicativeForConst[C](implicit C: Monoid[C]): Applicative[Const[C, *]] =
196228
new ConstApplicative[C] { val C0: Monoid[C] = C }
197-
}
198-
199-
sealed abstract private[data] class ConstInstances3 extends ConstInstances4 {
200-
implicit def catsDataEqForConst[A: Eq, B]: Eq[Const[A, B]] = _ === _
201229

202230
implicit def catsDataApplyForConst[C](implicit C: Semigroup[C]): Apply[Const[C, *]] =
203231
new ConstApply[C] { val C0: Semigroup[C] = C }
204232
}
205233

206-
sealed abstract private[data] class ConstInstances4 {
234+
sealed abstract private[data] class ConstInstances3 extends ConstInstances4 {
207235

208-
implicit def catsDataFunctorForConst[C]: Functor[Const[C, *]] =
236+
@deprecated("Use catsDataTraverseForConst instead", "2.10.0")
237+
def catsDataFunctorForConst[C]: Functor[Const[C, *]] =
209238
new ConstFunctor[C] {}
210239

211240
implicit def catsDataContravariantForConst[C]: Contravariant[Const[C, *]] =
212241
new ConstContravariant[C] {}
213242
}
214243

244+
sealed abstract private[data] class ConstInstances4
245+
215246
sealed private[data] trait ConstFunctor[C] extends Functor[Const[C, *]] {
216-
def map[A, B](fa: Const[C, A])(f: A => B): Const[C, B] =
247+
final override def map[A, B](fa: Const[C, A])(f: A => B): Const[C, B] =
217248
fa.retag[B]
218249
}
219250

@@ -233,7 +264,7 @@ sealed private[data] trait ConstApply[C] extends ConstFunctor[C] with Apply[Cons
233264
fa.retag[(A, B)].combine(fb.retag[(A, B)])
234265
}
235266

236-
sealed private[data] trait ConstApplicative[C] extends ConstApply[C] with Applicative[Const[C, *]] {
267+
sealed private[data] trait ConstApplicative[C] extends Applicative[Const[C, *]] with ConstApply[C] {
237268

238269
implicit def C0: Monoid[C]
239270

tests/shared/src/test/scala/cats/tests/ConstSuite.scala

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,20 @@ import cats.data.{Const, NonEmptyList}
2626
import cats.kernel.Semigroup
2727
import cats.kernel.laws.discipline.{
2828
EqTests,
29+
HashTests,
2930
LowerBoundedTests,
3031
MonoidTests,
3132
OrderTests,
3233
PartialOrderTests,
3334
SemigroupTests,
3435
UpperBoundedTests
3536
}
36-
import cats.laws.discipline._
3737
import cats.laws.discipline.SemigroupalTests.Isomorphisms
38+
import cats.laws.discipline._
3839
import cats.laws.discipline.arbitrary._
39-
import cats.syntax.show._
40-
import cats.tests.Helpers.{CMono, CSemi}
4140
import cats.syntax.eq._
41+
import cats.syntax.show._
42+
import cats.tests.Helpers.{CMono, CSemi, Semi}
4243
import org.scalacheck.Prop._
4344

4445
class ConstSuite extends CatsSuite {
@@ -100,9 +101,16 @@ class ConstSuite extends CatsSuite {
100101
checkAll("Const[String, Int]", ContravariantTests[Const[String, *]].contravariant[Int, Int, Int])
101102
checkAll("Contravariant[Const[String, *]]", SerializableTests.serializable(Contravariant[Const[String, *]]))
102103

103-
checkAll("Const[String, Int]", ContravariantMonoidalTests[Const[String, *]].contravariantMonoidal[Int, Int, Int])
104-
checkAll("ContravariantMonoidal[Const[String, *]]",
105-
SerializableTests.serializable(ContravariantMonoidal[Const[String, *]])
104+
checkAll("ContravariantMonoidal[Const[Int, *]]",
105+
ContravariantMonoidalTests[Const[Int, *]].contravariantMonoidal[Int, Int, Int]
106+
)
107+
checkAll("ContravariantMonoidal[Const[Int, *]]", SerializableTests.serializable(ContravariantMonoidal[Const[Int, *]]))
108+
109+
checkAll("ContravariantSemigroupal[Const[Semi, *]]",
110+
ContravariantSemigroupalTests[Const[Semi, *]].contravariantSemigroupal[Int, Int, Int]
111+
)
112+
checkAll("ContravariantSemigroupal[Const[Semi, *]]",
113+
SerializableTests.serializable(ContravariantSemigroupal[Const[Semi, *]])
106114
)
107115

108116
checkAll("Const[*, *]", BifoldableTests[Const].bifoldable[Int, Int, Int])
@@ -120,8 +128,8 @@ class ConstSuite extends CatsSuite {
120128
forAll { (const: Const[Int, String]) =>
121129
assert(const.show.startsWith("Const(") === true)
122130
const.show.contains(const.getConst.show)
123-
assert(const.show === (implicitly[Show[Const[Int, String]]].show(const)))
124-
assert(const.show === (const.retag[Boolean].show))
131+
assert(const.show === Show[Const[Int, String]].show(const))
132+
assert(const.show === const.retag[Boolean].show)
125133
}
126134
}
127135

@@ -130,7 +138,7 @@ class ConstSuite extends CatsSuite {
130138

131139
{
132140
implicit val iso: Isomorphisms[Const[CMono, *]] =
133-
Isomorphisms.invariant[Const[CMono, *]](Const.catsDataFunctorForConst)
141+
Isomorphisms.invariant[Const[CMono, *]](Const.catsDataTraverseForConst)
134142
checkAll("Const[CMono, Int]", CommutativeApplicativeTests[Const[CMono, *]].commutativeApplicative[Int, Int, Int])
135143
checkAll("CommutativeApplicative[Const[CMono, *]]",
136144
SerializableTests.serializable(CommutativeApplicative[Const[CMono, *]])
@@ -139,4 +147,23 @@ class ConstSuite extends CatsSuite {
139147

140148
checkAll("Const[CSemi, Int]", CommutativeApplyTests[Const[CSemi, *]].commutativeApply[Int, Int, Int])
141149
checkAll("CommutativeApply[Const[CSemi, *]]", SerializableTests.serializable(CommutativeApply[Const[CSemi, *]]))
150+
151+
checkAll("Hash[Const[Int, String]]", HashTests[Const[Int, String]].hash)
152+
checkAll("Hash[Const[Int, String]]", SerializableTests.serializable(Hash[Const[Int, String]]))
153+
154+
checkAll("MonoidK[Const[Int, *]]", MonoidKTests[Const[Int, *]].monoidK[Int])
155+
checkAll("MonoidK[Const[Int, *]]", SerializableTests.serializable(MonoidK[Const[Int, *]]))
156+
157+
checkAll("SemigroupK[Const[Int, *]]", SemigroupKTests[Const[Semi, *]].semigroupK[Int])
158+
checkAll("SemigroupK[Const[Int, *]]", SerializableTests.serializable(SemigroupK[Const[Semi, *]]))
159+
}
160+
161+
object ConstSuite {
162+
def summonInstances[A, B: Hash](): Unit = {
163+
InvariantMonoidal[Const[Int, *]]
164+
Invariant[Const[A, *]]
165+
Functor[Const[A, *]]
166+
Eq[Const[B, Int]]
167+
()
168+
}
142169
}

0 commit comments

Comments
 (0)