在scala 2.13中,为什么有时无法显式调用类型类?- 第2部分

15 浏览
0 Comments

在scala 2.13中,为什么有时无法显式调用类型类?- 第2部分

这是对In scala 2.13, why is it sometimes impossible to summon type class explicitly?的后续问题:

以下代码可以正确编译:

  import shapeless._
  import record._
  import syntax.singleton._
  val book =
    ("author" ->> "Benjamin Pierce") ::
      ("title" ->> "Types and Programming Languages") ::
      ("id" ->> 262162091) ::
      ("price" ->> 44.11) ::
      HNil
  val v1 = book.values
  assert(v1.head == "Benjamin Pierce")
  case class HasValues[T <: HList: TypeTag](v: T) {
//    def vs(implicit v: Values[T]) = v // doesn't work
    def vs(implicit v: Values[T]): Values.Aux[T, v.Out] = v // works
  }
  val _vs = HasValues(book).vs
  val v2 = book.values(_vs)
  assert(v2.head == "Benjamin Pierce")

而以下代码,在编译时和运行时都是语法上相同的,却编译失败了:

  import shapeless._
  import record._
  import syntax.singleton._
  val book =
    ("author" ->> "Benjamin Pierce") ::
      ("title" ->> "Types and Programming Languages") ::
      ("id" ->> 262162091) ::
      ("price" ->> 44.11) ::
      HNil
  val v1 = book.values
  assert(v1.head == "Benjamin Pierce")
  case class HasValues[T <: HList: TypeTag](v: T) {
    type TT = T
  }
  val hv = HasValues(book)
  val _vs = implicitly[Values[hv.TT]]
  val _vs2: Values.Aux[hv.TT, _vs.Out] = _vs
  val v2 = book.values(_vs2)
  assert(v2.head == "Benjamin Pierce")

结果:

[Error] /home/peng/git-spike/scalaspike/common/src/test/scala/com/tribbloids/spike/shapeless_spike/RecordProblem2.scala:41: could not find implicit value for parameter c: shapeless.ops.hlist.IsHCons[com.tribbloids.spike.shapeless_spike.RecordProblem2._vs2.Out]
one error found

此外,以下这行代码似乎非常繁琐。理想情况下,我认为编译器应该能够自动推导出这个细化类型,考虑到这完全是一个向上转型:

  val _vs = implicitly[Values[hv.TT]]
  val _vs2: Values.Aux[hv.TT, _vs.Out] = _vs

为什么第二个代码编译失败,更进一步,如何摆脱这种样板式的鸭子类型声明?(当然,不能修改HasValues类的签名)

0
0 Comments

在Scala 2.13中,有时无法显式调用类型类的原因是implicitly可以破坏类型细化。解决方法是使用shapeless.the代替。

以下是解决问题的代码示例:

val hv = HasValues(book)
val _vs = the[Values[hv.TT]]
val _vs2: Values.Aux[hv.TT, _vs.Out] = _vs
val v2 = book.values(_vs2)
assert(v2.head == "Benjamin Pierce")

另外,以下代码也可以编译通过:

val hv = HasValues(book)
val _vs2 = the[Values[hv.TT]]
val v2 = book.values(_vs2)
assert(v2.head == "Benjamin Pierce")

val hv = HasValues(book)
val v2 = book.values
assert(v2.head == "Benjamin Pierce")

此外,可以将以下代码:

def vs(implicit v: Values[T]): Values.Aux[T, v.Out] = v

替换为:

def vs(implicit v: Values[T]): v.type = v

0