Shapeless中TypeClass特征的emptyCoproduct和coproduct方法的目的是什么 [英] What is the purpose of the emptyCoproduct and coproduct methods of the TypeClass trait in Shapeless
问题描述
我还不太清楚Shapeless中TypeClass
特征的emptyCoProduct
和coproduct
方法的目的是什么.
It is not fully clear to me what is the purpose of the emptyCoProduct
and coproduct
methods of the TypeClass
trait in Shapeless.
何时会使用TypeClass
特征而不是ProductTypeClass
?
When would one use the TypeClass
trait instead of the ProductTypeClass
?
这两种方法的实现方式有哪些示例?
What are some examples of ways those two methods would be implemented?
推荐答案
假设我有一个简单的类型类:
Suppose I've got a simple type class:
trait Weight[A] { def apply(a: A): Int }
object Weight {
def apply[A](f: A => Int) = new Weight[A] { def apply(a: A) = f(a) }
}
还有一些实例:
implicit val stringWeight: Weight[String] = Weight(_.size)
implicit def intWeight: Weight[Int] = Weight(identity)
还有一个案例类:
case class Foo(i: Int, s: String)
还有ADT:
sealed trait Root
case class Bar(i: Int) extends Root
case class Baz(s: String) extends Root
我可以为我的类型类定义一个ProductTypeClass
实例:
I can define a ProductTypeClass
instance for my type class:
import shapeless._
implicit object WeightTypeClass extends ProductTypeClass[Weight] {
def emptyProduct: Weight[HNil] = Weight(_ => 0)
def product[H, T <: HList](hw: Weight[H], tw: Weight[T]): Weight[H :: T] =
Weight { case (h :: t) => hw(h) + tw(t) }
def project[F, G](w: => Weight[G], to: F => G, from: G => F): Weight[F] =
Weight(f => w(to(f)))
}
并像这样使用它:
scala> object WeightHelper extends ProductTypeClassCompanion[Weight]
defined object WeightHelper
scala> import WeightHelper.auto._
import WeightHelper.auto._
scala> implicitly[Weight[Foo]]
res0: Weight[Foo] = Weight$$anon$1@4daf1b4d
scala> implicitly[Weight[Bar]]
res1: Weight[Bar] = Weight$$anon$1@1cb152bb
scala> implicitly[Weight[Baz]]
res2: Weight[Baz] = Weight$$anon$1@74930887
但是!
scala> implicitly[Weight[Root]]
<console>:21: error: could not find implicit value for parameter e: Weight[Root]
implicitly[Weight[Root]]
^
这是一个问题-它使我们的自动类型类实例派生对于ADT几乎毫无用处.幸运的是,我们可以改用TypeClass
This is a problem—it makes our automated type class instance derivation pretty much useless for ADTs. Fortunately we can use TypeClass
instead:
implicit object WeightTypeClass extends TypeClass[Weight] {
def emptyProduct: Weight[HNil] = Weight(_ => 0)
def product[H, T <: HList](hw: Weight[H], tw: Weight[T]): Weight[H :: T] =
Weight { case (h :: t) => hw(h) + tw(t) }
def project[F, G](w: => Weight[G], to: F => G, from: G => F): Weight[F] =
Weight(f => w(to(f)))
def emptyCoproduct: Weight[CNil] = Weight(_ => 0)
def coproduct[L, R <: Coproduct]
(lw: => Weight[L], rw: => Weight[R]): Weight[L :+: R] = Weight {
case Inl(h) => lw(h)
case Inr(t) => rw(t)
}
}
然后:
scala> object WeightHelper extends TypeClassCompanion[Weight]
defined object WeightHelper
scala> import WeightHelper.auto._
import WeightHelper.auto._
scala> implicitly[Weight[Root]]
res0: Weight[Root] = Weight$$anon$1@7bc44e19
上面的所有其他内容仍然有效.
All the other stuff above still works as well.
总结:Shapeless的Coproduct
是对ADT的一种抽象,通常应为类型类提供TypeClass
的实例,而不是尽可能地仅提供ProductTypeClass
.
To sum up: Shapeless's Coproduct
is a kind of abstraction over ADTs, and in general you should provide instances of TypeClass
for your type classes instead of just ProductTypeClass
whenever possible.
这篇关于Shapeless中TypeClass特征的emptyCoproduct和coproduct方法的目的是什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!