En Scala, ¿es posible recuperar el `Val` referido por un tipo Singleton?
-
27-10-2019 - |
Pregunta
Estoy tratando de obtener una forma mínima de tipos dependientes en Scala. Si tengo
class A[T <: Int]
val x: Int = 7
puedo
val a = new A[x.type]
Ahora es posible recuperar x
de su singleton x.type
?
O, si eso no es posible, ¿es posible asociar un identificador estable con un tipo de alguna manera y luego extraerlo?
Solución
No, no puedes recuperarte x
de x.type
Debido a la borrado tipo JVM. Por ejemplo, ¿cómo se implementaría esto?
def f[A]: A = ???
f[x.type]
En el nivel de código de bytecodo JVM, no hay forma de que f
puede encontrar valor x: A
dado A = x.type
Porque no tiene nada con lo que trabajar: todos los parámetros de tipo se pierden en el tiempo de ejecución, y de todos modos, el x
El valor no está disponible en f
Pila de parámetros.
Por la misma razón, para obtener un tipo estable de tipo, tendría que reificarlo como un Manifest
valor. Pero cuando lo intenté, obtengo un resultado extraño,
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 !?
No estoy seguro de por qué estos dos manifiestos de tipo son iguales, incluso tienen diferentes toString
representaciones. ¿Podría ser este un error de Scala? Actualizar: De acuerdo con la Scaladoc, Los operadores de relación de tipo <: <y =: = deben considerarse aproximaciones solo, ya que existen numerosos aspectos de conformidad de tipo que aún no se representan adecuadamente en los manifiestos.
Para resumir, la reificación de la información de tipo en valores de tiempo de ejecución no ocurre automáticamente en el JVM. Scala Manifest
Se supone que llena el vacío, pero supongo que no funciona con tipos dependientes.
Otros consejos
Para responder a su segunda pregunta, "asociar un identificador estable a un tipo", una forma de hacerlo es usar clases de tipo. Digamos que quiero asociar una descripción de una cadena a los tipos, puedo hacerlo de la siguiente manera:
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"
}
Ahora, para recuperar tales etiquetas, ingrese la magia implícita:
def printTag[T : Tag] {
val tag = implicitly[Tag[T]]
println("Type is described as : " + tag.desc)
}
P.ej:
printTag[String] // prints "Type is described as : character string"
printTag[Double] // compile-time error: no implicit value found of type Tag[Double]
Incluso puede generar etiquetas según sea necesario, utilizando funciones implícitas. Por ejemplo:
implicit def liftTagToList[T : Tag] = new Tag[List[T]] {
val underlying = implicitly[Tag[T]].desc
val desc = "list of " + underlying + "s"
}
Ahora puedo hacer lo siguiente:
// prints "Type is described as : list of character strings"
printTag[List[String]]
E incluso:
// prints "Type is described as : list of list of character stringss"
printTag[List[List[String]]]
Por favor, perdona la pluralización.