Shapeless中TypeClass特征的emptyCoproduct和coproduct方法的目的是什么 [英] What is the purpose of the emptyCoproduct and coproduct methods of the TypeClass trait in Shapeless

查看:135
本文介绍了Shapeless中TypeClass特征的emptyCoproduct和coproduct方法的目的是什么的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我还不太清楚Shapeless中TypeClass特征的emptyCoProductcoproduct方法的目的是什么.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆