Scala递归类型的问题(构建Hlist)

时间:2016-04-28 15:15:43

标签: scala

我正在尝试为a small Scala utility lib构建异构列表递归类型。 我有问题要连接2 Hlist并保持一致的类型。

trait HList {
  def ::[U](v: U): HList
}

class HNil extends HList {
  override def ::[T](v: T) = HCons(v, this)
}    

case object HNil extends HNil

case class HCons[T, U <: HList](head: T, tail: U) extends HList {

  def ++[V <: HList, R <: HList](l2: V): HCons[T, R] = {
    def append(l1: HCons[T, _], l2: V): HCons[T, _] = {
      l1.tail match {
        case HNil => HCons(l1.head, l2)
        case h: HCons[T, U] => l1.head :: append(h, l2)
      }
    }
    append(this, l2) match {
      case h: HCons[T,R] => h
    }
  }
}

这是有效的,所以在运行时类型没问题:

val sum = (2.0 :: "hi" :: HNil) ++ (1 :: HNil)
sum shouldBe 2.0 :: "hi" :: 1 :: HNil
sum shouldBe a[HCons[_, HCons[_, HCons[_, HNil]]]]

但以下代码未编译:

val sum = (2.0 :: "hi" :: HNil) ++ (1 :: HNil)
sum.tail.head

value head is not a member of Nothing

你知道如何告诉计算机选择sum.tail的正确类型,即HCons [Int,HNil]吗?

谢谢:)

1 个答案:

答案 0 :(得分:1)

基本上,编译器不能仅从参数类型确定结果类型R。如果你看,你实际上没有任何代码可以确定它。所以编译器选择Nothing

为了解决这个问题,我认为最小的解决方案是使用带有Appender类型类的内部类型,而不是直接在HCons内部实现,就像你在这里一样。

写出比我更好的完整解决方案:http://jnordenberg.blogspot.co.uk/2008/08/hlist-in-scala.html