4

我试图在 Scala 中获得最小形式的依赖类型。如果我有

class A[T <: Int]

val x: Int = 7

我可以

val a = new A[x.type]

现在有可能x从它的单例中恢复x.type吗?

或者,如果这不可能,是否可以以某种方式将稳定标识符与类型相关联,然后提取它?

4

2 回答 2

6

不,由于 JVM 类型擦除,您无法x从中恢复。x.type例如,这将如何实现?

def f[A]: A = ???
f[x.type]

在 JVM 字节码级别,没有办法f找到x: A给定的值,A = x.type因为它没有任何东西可以使用:所有类型参数在运行时都会丢失,无论如何,该值在的参数堆栈x上不可用。f

出于同样的原因,要获得一个类型的稳定 ID,您必须将其具体化为一个Manifest值。但是当我尝试时,我得到了一个奇怪的结果,

def f[A : Manifest] = implicitly[Manifest[A]]
val x = "hi"
val y = "ho"
println(f[x.type]) // hi.type
println(f[y.type]) // ho.type
f[x.type] == f[y.type] // true !?

我不确定为什么这两种类型的清单是相等的——它们甚至有不同的toString表示。这可能是Scala错误吗?更新:根据ScalaDoc类型关系运算符 <:< 和 =:= 应仅视为近似值,因为类型一致性的许多方面尚未在清单中充分表示。

总而言之,将类型信息具体化为运行时值不会在 JVM 上自动发生。ScalaManifest应该可以填补这个空白,但我想它不适用于依赖类型。

于 2011-09-08T05:26:38.037 回答
3

要回答您的第二个问题,“将稳定的标识符与类型相关联”,一种方法是使用类型类。假设我想将字符串描述与类型相关联,我可以这样做:

trait Tag[A] {
  val desc : String
}

implicit object StringTag extends Tag[String] {
  val desc = "character string"
}

implicit object IntTag extends Tag[Int] {
  val desc = "32-bit integer"
}

现在,要恢复此类标签,请输入隐式魔法:

def printTag[T : Tag] {
  val tag = implicitly[Tag[T]]
  println("Type is described as : " + tag.desc)
}

例如:

printTag[String] // prints "Type is described as : character string"
printTag[Double] // compile-time error: no implicit value found of type Tag[Double]

您甚至可以根据需要使用隐式函数生成标签。例如:

implicit def liftTagToList[T : Tag] = new Tag[List[T]] {
  val underlying = implicitly[Tag[T]].desc
  val desc = "list of " + underlying + "s"
}

我现在可以执行以下操作:

// prints "Type is described as : list of character strings"
printTag[List[String]]

乃至:

// prints "Type is described as : list of list of character stringss"
printTag[List[List[String]]]

请原谅复数。

于 2011-09-08T18:24:43.140 回答