2012-05-16 17 views
6

Estoy intentando parametrizar algunos métodos con parámetros de tipo muy generales.Tipos de Scala: menos límites superiores

Como un ejemplo, en el REPL I primero definir:

trait Term 
case class FunctionalTerm[+T <: Term](t: T) extends Term 

Intuitivamente, el siguiente método toma un plazo y un FunctionalTerm, y devuelve algo con el tipo de la cota superior mínima del tipo de término pasado y el tipo de argumento de FunctionalTerm:

def ex1[T1 <: Term, T3 <: X, FunctionalTerm[T1] <: X, X <: R, R <: Term](t1: FunctionalTerm[T1], s: T3): R = sys.error("TODO") 

Hasta ahora todo bien en el REPL.

Entonces definen ex2 como una función de conveniencia que realiza la misma operación como ex1, pero con los argumentos de entrada intercambiados:

def ex2[T2 <: Term, T3 <: X, FunctionalTerm[T2] <: X, X <: R, R <: Term](s: T3, t2: FunctionalTerm[T2]): R = ex1(t2,s) 

El intento de definir ex2 en el REPL da el siguiente error:

error: inferred type arguments [T2,T3,FunctionalTerm,T3,T3] do not conform to method ex1's type parameter bounds [T1 <: Term,T3 <: X,FunctionalTerm[T1] <: X,X <: R,R <: Term] 
     ex1(t2,s) 
     ^
error: type mismatch; 
found : FunctionalTerm[T2] 
required: FunctionalTerm[T1] 
     ex1(t2,s) 
      ^
error: type mismatch; 
found : T3(in method ex2) 
required: T3(in method ex1) 
     ex1(t2,s) 
       ^
error: type mismatch; 
found : R(in method ex1) 
required: R(in method ex2) 
     ex1(t2,s) 
      ^

He pasado aproximadamente dos días tratando de encontrar una solución, y ahora estoy totalmente atascado. No puedo encontrar nada más en Google.

Desde la lista de argumentos de tipo ex2 es el mismo que el de ex1 pero con T1 y T2 intercambiado, no entiendo que está mal, o cómo solucionarlo.

¡Cualquier ayuda sería muy apreciada!

actualización

menos límites superiores eran una cortina de humo. El ejemplo se puede destilar más.

Las siguientes dos funciones se pueden definir en el REPL sin error:

def ex1[T1 <: Term, FunctionalTerm[T1] <: Term](t1: FunctionalTerm[T1]): Term = sys.error("TODO: ex1") 
def ex2[T2 <: Term, FunctionalTerm[T2] <: Term](t2: FunctionalTerm[T2]): Term = ex1(t2) 

Al presentar el parámetro extra X parece ser la causa del problema. Puedo definir lo siguiente en el REPL:

def ex3[T1 <: Term, FunctionalTerm[T1] <: X, X <: Term](t1: FunctionalTerm[T1]): Term = sys.error("TODO: ex3") 

Pero tratar de definir posteriormente:

def ex4[T2 <: Term, FunctionalTerm[T2] <: X, X <: Term](t2: FunctionalTerm[T2]): Term = ex3(t2) 

da el error:

error: inferred type arguments [T2,FunctionalTerm,Nothing] do not conform to method ex3's type parameter bounds [T1 <: Term,FunctionalTerm[T1] <: X,X <: Term] 
     def ex4[T2 <: Term, FunctionalTerm[T2] <: X, X <: Term](t2: FunctionalTerm[T2]): Term = ex3(t2) 
                          ^
error: type mismatch; 
found : FunctionalTerm[T2] 
required: FunctionalTerm[T1] 
     def ex4[T2 <: Term, FunctionalTerm[T2] <: X, X <: Term](t2: FunctionalTerm[T2]): Term = ex3(t2) 
                           ^

lo tanto, supongo que la pregunta es: ¿Por qué el parámetro X no utilizado en la firma tiene este efecto?

+0

me olvidó decir que estoy usando Scala 2.10-M3. –

+0

No está utilizando tipos superiores, aunque :-) –

+0

@oxbow_lakes Oh ... corregiré –

Respuesta

5

No estoy seguro de si está experimentando o no un error, pero estoy bastante seguro de que está haciendo su vida mucho más difícil de lo que debe ser. Puede depender de covarianza y la unificación de hacer todo el trabajo duro por ti,

scala> trait Term 
defined trait Term 

scala> case class FunctionalTerm[+T <: Term](t: T) extends Term 
defined class FunctionalTerm 

scala> def ex1[T <: Term](t1 : FunctionalTerm[T], s : T) : T = s 
ex1: [T <: Term](t1: FunctionalTerm[T], s: T)T 

scala> class A extends Term ; class B extends A ; class C extends A 
defined class A 
defined class B 
defined class C 
scala> ex1(new FunctionalTerm(new B), new C) 
res0: A = [email protected] 

Nota el tipo de resultado inferida (que es equivalente a la R del original de manera más compleja la definición) ... es que es el A LUB de B y C.

Ahora la versión volteada es trivial y simplemente funciona,

scala> def ex2[T <: Term](s : T, t1 : FunctionalTerm[T]) : T = s 
ex2: [T <: Term](s: T, t1: FunctionalTerm[T])T 

scala> ex2(new C, new FunctionalTerm(new B)) 
res1: A = [email protected] 
+1

Resulta que el comportamiento reportado NO es un error. El uso de FunctionalTerm [T1] <: X y FunctionalTerm [T2] <: X en el ejemplo original declaró un parámetro de tipo de método llamado "FunctionalTerm" que no está relacionado con la clase de caso con el mismo nombre. Sin embargo, estoy marcando esto como la respuesta, ya que lo sugerido logró lo que necesitaba hacer. –

+0

¡Bien, duh! ... increíble que ni yo ni @oxbow_lakes notamos eso! –

2

Voy a simplificar su ejemplo (estoy usando 2.9.1):

scala> trait Term; case class FunctionalTerm[+T <: Term](t: T) extends Term; 
defined trait Term 
defined class FunctionalTerm 

scala> def ex1[T1 <: Term, T3 <: X, FunctionalTerm[T1] <: X, X <: R, R <: Term](t1: FunctionalTerm[T1], s: T3): R = sys.error("TODO") 
ex1: [T1 <: Term, T3 <: X, FunctionalTerm[T1] <: X, X <: R, R <: Term](t1: FunctionalTerm[T1], s: T3)R 

Ahora declarando el segundo método:

scala> def ex2[T2 <: Term, T3 <: X, FunctionalTerm[T2] <: X, X <: R, R <: Term](s: T3, t2: FunctionalTerm[T2]): R = ex1(t2, s) 
<console>:11: error: inferred type arguments [T2,T3,FunctionalTerm,T3,T3] do not conform to method ex1's type parameter bounds [T1 <: Term,T3 <: X,FunctionalTerm[T1] <: X,X <: R,R <: Term] 
     def ex2[T2 <: Term, T3 <: X, FunctionalTerm[T2] <: X, X <: R, R <: Term](s: T3, t2: FunctionalTerm[T2]): R = ex1(t2, s) 
                                ^

El sospechosa cosa (me) es los tipos inferidos [T2,T3,FunctionalTerm,T3,T3] - en particular FunctionalTerm. FunctionalTerm es un tipo constructor* -> * pero el método espera un tipo * en esta posición.

Yo diría que este es (supuestamente) un error y por lo tanto se deben someter a la lista de correo scala-usuario (antes de levantar un boleto) - Adriaan moros y Miles Sabin son mucho más propensos a tener una respuesta detallada sobre si estoy en lo correcto.

+0

Muchas gracias, sospeché que era un error, pero mi conocimiento limitado de los tipos me hizo ser cauteloso. Actualizaré cuando tenga algo resuelto. –

Cuestiones relacionadas