2011-12-18 10 views
5
def foo(num:Int, str:String):Int = 1 

val bar = foo(3, _) // compiler complains "missing parameter type for expanded function ((x$1) => test(3, x$1))" 

val baz = foo(3, _:String) // compiles fine 

¿Por qué tengo que especificar explícitamente el tipo de _ cuando parece inferible desde el contexto?información de tipo de parámetro redundante en la definición de función parcialmente aplicada

EDIT: Se ha cambiado el nombre para evitar colisiones de nombres después de la sugerencia de David Soergel.

Respuesta

3

En primer lugar, para evitar la confusión entre "prueba de def" y "prueba de val", vamos a escribir:

def foo(num:Int, str:String):Int = 1 

val bar = foo(3, _) // compiler complains "missing parameter type for expanded function ((x$1) => foo(3, x$1))" 

val baz = foo(3, _:String) // compiles fine 

¿Qué hay infieren a partir del contexto es sólo que el argumento a la barra debe ser de algún modo convertible en una cadena . Eso podría deberse a la herencia (si en lugar de String utiliza algún tipo no final allí), o debido a una conversión implícita.

Básicamente el potencial para implícitos significa que el argumento a la barra podría ser casi cualquier tipo en absoluto, así como el código escrito es de hecho underspecified. No sé si el compilador comprueba efectivamente si hay conversiones implícitas apropiadas en el alcance antes de emitir el error "que falta", pero yo no adivinar. (En el caso de String es probable que haya un grupo presente, de todos modos). Sería frágil y confuso si la firma de baz cambiara como resultado de la importación de un nuevo implícito que podría producir una Cadena.

+1

Gracias por la corrección de nombre. Pero 'def foo (num: Int) = 1; val bar = foo (_) 'compila bien. Por lo tanto, no creo que la herencia o las conversiones implícitas causen el error. – xiefei

+0

Huh-- Lo sentimos, una reflexión más profunda sobre mi argumento implícitos no tiene sentido de todos modos. El compilador podría de hecho deducir el tipo de argumento de la barra como Cadena, y luego permitir implicitos al llamar a la barra, como de costumbre. –

3

creo que la explicación de David Soergel es esencialmente correcta: si el tipo de T tiene una conversión implícita a continuación Cadena val bar = foo(3, _:T) es válida, dando una función del tipo T => Int, que no está relacionado con String => Int.

Por qué el compilador no hace una suposición razonable (a falta de tipado explícito) de que el tipo es de hecho el mismo que en el método (que es la esencia de su pregunta), no sé - Solo puedo adivinar que es porque complicaría las especificaciones del lenguaje.

Cuando no se especifican tipos, es decir val bar = foo(_, _), parece que el compilador lo interpreta como sencilla eta-conversión, el mismo que val bar = foo _, que da una String => Int.

Mi idioma preferido sería dar el tipo de función en el lado izquierdo, el cual tiene la ventaja de que le permite ver fácilmente bar 's Tipo:

val bar: String => Int = foo(3, _) 

Si usted es alérgico a volver escribiendo la palabra String, puede escribir

val bar = (foo _).curried(3) 
+0

"Sintaxis de marcador de posición para funciones anónimas" parte de la especificación scala (2.8) no proporciona información sobre cómo se deduce el tipo de "_". La falta de especificaciones podría ser la causa de esta incoherencia del compilador. – xiefei

Cuestiones relacionadas