在运行时恢复依赖类型

时间:2015-07-22 06:33:25

标签: scala dependent-type path-dependent-type

我正在尝试在运行时恢复Scala中的依赖类型。我基本上想要归档一个类型保存映射,其中每个键都有一个关联的类型,但是Map的用户看不到所存储的键值对的所有类型信息(与真棒Shapeless Map不同)。 / p>

class Key[V] {
  type Value = V
  def ->(value: V) = Pair(this, value)
}
trait Pair {
  val key: Key[_]
  val value: key.Value
}
trait Map {
  val pairs: Seq[Pair]
  def get[V](key: Key[V]): Option[V] =
    pairs.find(pair => pair.key eq key).map(_.value).asInstanceOf[Option[V]]
    //                          ^                              ^
    //   the runtime prove that pair.key.Value equals V        |
    //                                                         |
    //                        'Convince' the compile that I know what I do
}

用法:

val text = new Key[String]
val count = new Key[Int]
val map: Map = new Map { val pairs = text -> "Hello World!" :: Nil }

map.get(text)  // Some(Hello World!), Type: Option[String]
map.get(count) // None, Type: Option[Int]

是否可以编写get方法而不使用带asInstanceOf的强制转换或隐式匹配未经检查的分支?

我尝试为成对编写unapply,但遇到了同样的问题。

请注意,我省略了Pair-companion对象的定义。这是Gist中的一个正在运行的示例。

2 个答案:

答案 0 :(得分:1)

请记住,JVM会在运行时删除泛型。所以任何依赖于泛型的东西,包括依赖类型,都只能在编译时发生 - 即在调用者中,因为任何给定的方法只能编译到一个运行时代码路径。唯一的选择是检查运行时类(直接或通过模式匹配),如你所说。 (如果沿着那条路走下去,Shapeless有一个类型安全的,类型类驱动的帮助器)

在没有类型问题的情况下,可能有一种聪明的方式来表达您的要求,但通常,类型信息必须对调用者可见或在运行时检查。

答案 1 :(得分:0)

解决您的类型问题的多种方法。首先定义问题的根源:

trait Map {
  val pairs: Seq[Pair]                     // (1)
  def get[V](key: Key[V]): Option[V] =     // (2)
    pairs.find(_.key eq key).map{_.value } // (3)
}
  1. pairs类型为Seq的{​​{1}}(带有一些嵌入的未定义类型Pair
  2. key: Key[_]类型为key,预期结果类型为Key[V]
  3. 尝试从(1)Option[V]而不是预期Key[_]返回类型并提取V
  4. 解决方案:您应该保证Key[V]嵌入式pairs与您返回的内容相同

    可能的解决方案之一:

    key