无形 .toHList 的行为

Behavior of shapeless .toHList

编译如下:

 object Run1 extends App {

  import shapeless._
  import syntax.std.traversable._

  case class Container[T](x: T)

  Seq(Container(1), Container("x")).toHList[Container[Int] :: Container[String] :: HNil]

}

但这不是:

object Run2 extends App {

  import shapeless._
  import syntax.std.traversable._

  class Container[T](val x: T)

  Seq(new Container(1), new Container("x")).toHList[Container[Int] :: Container[String] :: HNil]

}

失败并出现以下错误:

Error:(40, 52) could not find implicit value for parameter fl: shapeless.ops.traversable.FromTraversable[shapeless.::    [com.adaje.service.table.Run2.Container[Int],shapeless.::[com.adaje.service.table.Run2.Container[String],shapeless.HNil]]]
Seq(new Container(1), new Container("x")).toHList[Container[Int] :: Container[String] :: HNil]
                                               ^

为什么第二个程序不起作用,有什么可以添加的吗?

谢谢

FromTraversable 类型 class 需要 Typeable 个元素类型实例。 Shapeless 为案例 classes 提供了这些现成的,但不为任意定义的 classes。不过,您可以很容易地定义自己的:

import shapeless._, shapeless.syntax.std.traversable._

class Container[T](val x: T)

implicit def containerTypeable[A: Typeable]: Typeable[Container[A]] =
  new Typeable[Container[A]] {
    def cast(t: Any): Option[Container[A]] = t match {
      case c: Container[_] => Typeable[A].cast(c.x).map(new Container(_))
      case _ => None
    }

    def describe: String = s"Container[${ Typeable[A].describe }]"
  }

然后:

scala> val cs = Seq(new Container(1), new Container("x"))
cs: Seq[Container[_ >: String with Int]] = List(Container@3c3c89b2, Container@1273a053)

scala> cs.toHList[Container[Int] :: Container[String] :: HNil]
res0: Option[shapeless.::[Container[Int],shapeless.::[Container[String],shapeless.HNil]]] = Some(Container@357c808b :: Container@607bcaf5 :: HNil)

还有:

scala> cs.reverse.toHList[Container[Int] :: Container[String] :: HNil]
res1: Option[shapeless.::[Container[Int],shapeless.::[Container[String],shapeless.HNil]]] = None

scalac 的 -Xlog-implicits 选项在这种情况下会很方便——它会清楚地表明您最初的非 case-class 尝试中缺少的是 Typeable实例。