2011-04-04 12 views
10

¿Es posible utilizar el acceso directo de sintaxis de límites de contexto con tipos de caracteres más altos?Método abreviado de límites de contexto con tipos de caracteres más altos

trait One { def test[W : ClassManifest]: Unit } // first-order ok 
trait Two { def test[W[_]: ClassManifest]: Unit } // not possible?? 
trait Six { def test[W[_]](implicit m: ClassManifest[W[_]]): Unit } // hmm... 

Respuesta

11

Sí, lo es, pero su contexto tipo con destino debe tener un parámetro de tipo kinded más alta (que ClassManifest no lo hace).

scala> trait HKTypeClass[CC[_]] 
defined trait HKTypeClass 

scala> implicit def listHKTC = new HKTypeClass[List] {} 
listHKTC: java.lang.Object with HKTypeClass[List] 

scala> def frob[CC[_] : HKTypeClass] = implicitly[HKTypeClass[CC]] 
frob: [CC[_]](implicit evidence$1: HKTypeClass[CC])HKTypeClass[CC] 

scala> frob[List] 
res0: HKTypeClass[List] = [email protected] 

actualización

Es posible utilizar un alias tipo para permitir que un parámetro de tipo de mayor kinded a estar delimitado por un tipo unido contexto de primer orden. Usamos el alias de tipo como una función de nivel de tipo para hacer que un tipo de tipo superior sea del tipo de primer orden. Para ClassManifest podría ir así,

scala> type HKClassManifest[CC[_]] = ClassManifest[CC[_]] 
defined type alias HKClassManifest 

scala> def frob[CC[_] : HKClassManifest] = implicitly[HKClassManifest[CC]]   
test: [CC[_]](implicit evidence$1: HKClassManifest[CC])HKClassManifest[CC] 

scala> frob[List]              
res1: HKClassManifest[List] = scala.collection.immutable.List[Any] 

Tenga en cuenta que en el lado derecho del tipo de alias CC [_] es un tipo de primer orden ... el subrayado aquí es el comodín. En consecuencia, se puede utilizar como el argumento de tipo para ClassManifest.

actualización

Para completar Debo señalar que el alias tipo puede ser inline utilizando un tipo lambda,

scala> def frob[CC[_] : ({ type λ[X[_]] = ClassManifest[X[_]] })#λ] = implicitly[ClassManifest[CC[_]]]  
frob: [CC[_]](implicit evidence$1: scala.reflect.ClassManifest[CC[_]])scala.reflect.ClassManifest[CC[_]] 

scala> frob[List] 
res0: scala.reflect.ClassManifest[List[_]] = scala.collection.immutable.List[Any] 
+0

Pero 'ClassManifest' no necesita saber que su parámetro de tipo en sí mismo es más compatible de lo esperado, siempre y cuando los tipos superiores estén vinculados (incluso con un comodín), p. por qué no está permitida la 'prueba def [A, B [A]: ClassManifest] {}', aunque 'def test [A, B [A]] (implícita m: ClassManifest [B [A]]) {}' es ? –

+0

ClassManifest requiere que su argumento de tipo sea de primer orden, como puede ver si lo prueba implícitamente [ClassManifest [List]] en REPL. –

+0

Eso es lo que estoy diciendo: no importa si el tipo arg es de primer orden o de orden superior, siempre que se reduzca a primer orden: 'implícitamente [ClassManifest [List [_]]]' -> ok ! Así que me preguntaba por qué no puedo obtener el atajo para un contexto vinculado en este caso –

4

Tenga en cuenta que es la abreviatura de implicitly[ClassManifest[List[_]]]implicitly[ClassManifest[List[T] forSome {type T}]].

Es por eso que funciona: ClassManifest espera un argumento de tipo adecuado, y List[T] forSome {type T} es un tipo adecuado, pero List es un constructor de tipos. (Por favor, vea What is a higher kinded type in Scala? para una definición de "adecuada", etc.)

para que tanto ClassManifest[List[String]] y ClassManifest[List] trabajo, tendríamos que sobrecargar ClassManifest de alguna manera con las versiones que tienen parámetros de tipo para distintas clases, algo así como:

class ClassManifest[T] // proper type 
class ClassManifest[T[_]] // type constructor with one type parameter 
class ClassManifest[T[_, _]] // type constructor with two type parameters 
// ... ad nauseam 

(en una nota académica, la forma "correcta" de hacer esto, sería permitir que la abstracción sobre tipos:

class ClassManifest[T : K][K] 

    implicitly[ClassManifest[String]] // --> compiler infers ClassManifest[String][*] 
    implicitly[ClassManifest[List]] // --> compiler infers ClassManifest[List][* -> *] 

)

Cuestiones relacionadas