2012-02-08 12 views
7

Decir que tengo un tipo kinded mayorque limitan los tipos más altos-Kinded en Scala

SuperMap[Key[_],Value[_]]`. 

Supongamos ahora que tenía algo aún más específico que requiere que el parámetro de tipo para Key debe coincidir con el de Value; es decir, algo así como:

SuperDuperMap[T, Key[T], Value[T]] 

Además supongo que no quería cualquier T, pero una muy específica uno donde T <: OtherT

SuperDuperPooperMap[T <: OtherT, Key[T], Value[T]] 

se puede hacer esto en Scala? ¿Es esto solo una mala idea en general? ¿Hay una manera equivalente de hacer esto que sea más fácil de leer/escribir/usar?

Respuesta

11

su declaración ya que se supone que funciona, es decir, que está restringiendo el tipo de T, así como Key y Value. La forma en que se ha escrito, sin embargo, Scala se quejará si emite algo así como

scala> class Foo[T <: OtherT, Key[T], Value[T]] 
defined class Foo 

scala> new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]] 
<console>:13: error: Key[SpecialOtherT] takes no type parameters, expected: one 
       new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]] 

porque los tipos de tanto Key y Value ya son administradas por su declaración anterior. Por lo tanto, esto funcionará

scala> new Foo[SpecialOtherT, Key, Value] 
res20: Foo[SpecialOtherT,Key,Value] = [email protected] 

que probablemente no desee. Se podía haces así

scala> class Foo[T <: OtherT, K <: Key[T], V <: Value[T]] 
defined class Foo 

scala> new Foo[SpecialOtherT, Key[SpecialOtherT], Value[SpecialOtherT]] 
res21: Foo[SpecialOtherT,Key[SpecialOtherT],Value[SpecialOtherT]] = [email protected] 

En la línea inferior, ya que los tipos de Key y Value dependen únicamente de T es algo superfluo tener toda esa información redundante cuando se trabaja con Foo.¿Por qué no usar una declaración de tipo interior de esta manera:

class Foo[T <: OtherT] { 
    type K = Key[T] 
    type V = Value[T] 
} 

entonces tendría acceso a los tipos K y V desde dentro de la clase, pero no tendría que escribirla cada vez que se crea una nueva respuesta:

scala> new Foo[SpecialOtherT] 
res23: Foo[SpecialOtherT] = [email protected] 

scala> new Foo[Int] 
<console>:11: error: ... 
+0

¡Gracias! Muy informativo. Mi única respuesta a "Entonces, ¿por qué no utilizar una declaración de tipo interno?" Es que quiero inferir esos tipos para K y V en la creación de instancias. – duckworthd

+0

No estoy seguro de entender porque el tipo realmente se infiere. Dependiendo de su caso de uso, puede usar el tipo desde "afuera", p. Ej. 'clase Foo [T]; clase Bar [T] {tipo Wee = Foo [T]}; def doSomething [T] (b: Bar [T]) (implícito mf: Manifest [Bar [T] #Wee]) {Console println mf} ', y luego' doSomething (new Bar [Double]) '. De acuerdo, es un sucio ejemplo. – fotNelton

3

¿Se puede hacer esto en Scala?

¿Qué quiere decir? ¡Solo lo hiciste!

¿Es esto solo una mala idea en general?

¿Por qué sería? De hecho, esa es una gran idea! Esto es para lo que son los tipos de mayor nivel.

¿Hay una manera equivalente de hacer esto que sea más fácil de leer/escribir/usar?

Lectura - me lee bastante bien.

Escritura - escribir/probar/compilar una vez, usar en todas partes.

Usando - El compilador reconstruirá (inferirá) los tipos "en todas partes".

+0

Mientras mi código se compila, no se puede crear una instancia: X – duckworthd

2

Es probable que no necesita nada más complicado que un par de alias de tipo,

type SuperDuperMap[T, Key[_], Value[_]] = SuperMap[Key, Value] 

type SuperDuperPooperMap[T <: OtherT, Key[_], Value[_]] = SuperMap[Key, Value] 

ejemplo de sesión de REPL,

scala> new SuperDuperMap[Int, Option, List] {} 
res0: java.lang.Object with SuperDuperMap[Int,Option,List] = ... 

scala> new SuperDuperPooperMap[OtherT, Option, List] {} 
res1: java.lang.Object with SuperDuperPooperMap[OtherT,Option,List] = ... 
Cuestiones relacionadas