在具有子类型的类上创建 Scalaz 相等实例 [英] create Scalaz equal instance on class with subtypes
问题描述
我有以下简单的 ADT,如何在不诉诸显式模式匹配所有可能组合的情况下实现相等类型类的实例?
I have the following simple ADT, how would I implement an instance of the equality typeclass without resorting to explicitly pattern matching all possible combinations?
import scalaz._
import Scalaz._
sealed trait Billinginfo
case class CreditCard(number: Int, holder: String, Address: String) extends Billinginfo
case object COD extends Billinginfo
case class Invoice(cId: String) extends Billinginfo
object Billinginfo{
implicit val BillingEqual = Equal.equal[Billinginfo]{(b1,b2) =>
(b1,b2) match {
case (Invoice(c1), Invoice(c2)) => c1 === c2
case (CreditCard(a,b,c), CreditCard(d,e,f)) =>
a === d &&
b === e &&
c === f //writing exhaustive match would be tedious
}
}
推荐答案
您(至少)有两个选择.一种是使用自然"平等.如果您没有任何案例类成员的自定义类型,这应该可以正常工作:
You've got (at least) two options. One is to use "natural" equality. If you don't have any custom types for case class members this should work just fine:
implicit val BillingEqual: Equal[Billinginfo] = Equal.equalA[Billinginfo]
或者你可以使用Shapeless的类型类实例派生:
Or you could use Shapeless's type class instance derivation:
import shapeless._
import scalaz.{ Coproduct => _, :+: => _, _ }, Scalaz._
object EqualDerivedOrphans extends TypeClassCompanion[Equal] {
object typeClass extends TypeClass[Equal] {
def product[H, T <: HList](eh: Equal[H], et: Equal[T]): Equal[H :: T] =
tuple2Equal(eh, et).contramap {
case h :: t => (h, t)
}
def project[A, B](b: => Equal[B], ab: A => B, ba: B => A): Equal[A] =
b.contramap(ab)
def coproduct[L, R <: Coproduct](
el: => Equal[L],
er: => Equal[R]
): Equal[L :+: R] = eitherEqual(el, er).contramap {
case Inl(l) => Left(l)
case Inr(r) => Right(r)
}
val emptyProduct: Equal[HNil] = Equal.equal((_, _) => true)
val emptyCoproduct: Equal[CNil] = Equal.equal((_, _) => true)
}
}
import EqualDerivedOrphans._
这将为所有成员具有 Equal
实例的任何 case 类派生 Equal
实例.
This will derive Equal
instances for any case classes that have Equal
instances for all their members.
或者当然你可以列举案例,这实际上并没有那么糟糕:
Or of course you could enumerate the cases, which isn't actually that terrible:
implicit val BillingEqual = Equal.equal[Billinginfo] {
case (Invoice(c1), Invoice(c2)) => c1 === c2
case (CreditCard(a, b, c), CreditCard(d, e, f)) =>
a === d && b === e && c === f
case (COD, COD) => true
case _ => false
}
请注意,您不需要对元组进行额外级别的匹配.
Note that you don't need the extra level of matching on the tuple.
这篇关于在具有子类型的类上创建 Scalaz 相等实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!