2011-08-19 12 views
9

ver este ejemplo:¿Por qué Scala no puede inferir el tipo en un método parcial?

def hello(a:String, b:String) = println(a + ":" + b) 
val m1 = hello("aaa", _) 
m1("bbb") 

No puede ser compilado, que tengo que añadir el tipo con el método parcial:

val m1 = hello("aaa", _: String) 

Por qué Scala no se conoce el segundo parámetro del método hello es String?

Respuesta

15

La inferencia de tipo de Scala se basa en el flujo. Los métodos y las funciones necesitan tipos de parámetros explícitos, que se utilizan para inferir otros tipos. Los tipos de parámetros no pueden inferirse del método o del cuerpo de la función. A veces, sin embargo, los tipos de parámetros se conocen desde el contexto externo, y luego no tienen que estar etiquetados. Dos ejemplos,

val f: String => Unit = hello("aaa", _) 
val s = Seq(1,2).map(_+1) // Seq[Int].map expects a function of Int argument type 

A continuación se muestra una cita de Martin Odersky sobre las limitaciones de la inferencia de tipos de Scala en comparación con, por ejemplo, ML y Haskell. Los desafíos incluyen la sobrecarga de Scala, la selección de registros, y subtipos, así como la necesidad de mantener las cosas simples,

La razón Scala no tiene Hindley/Milner tipo de inferencia es que es muy difícil de combinar con características tales como sobrecarga (la variante ad-hoc , no las clases de tipo), selección de registro y subtipificación. No digo imposible: existen varias extensiones que incorporan estas características; de hecho, he sido guitly de algunos de ellos . Solo digo que es muy difícil hacer que esto funcione bien en la práctica , donde uno necesita expresiones de tipo pequeño y buenos mensajes de error . Tampoco es un caso cerrado: muchos investigadores están trabajando en para ampliar los límites aquí (por ejemplo, en el MLF de Remy). Pero en este momento es una compensación de mejor tipo de referencia vs mejor soporte para estas características. Puede hacer que las dos formas de compensación sean . El hecho de que quisiéramos integrar con Java inclinaba las escalas a favor de la subtipificación y de Hindley/Milner.

Fuente: comentario en la publicación Universal Type Inference is a Bad Thing.

3

Puede ser porque existe una ambigüedad potencial con esta definición ya que hello podría estar sobrecargado.

// inside some class context 
def hello(a:String, b:String) = println(a + ":" + b) 
def hello(a:String, b:Int) = println(a + ":" + b.toString) 
val m1 = hello("aaa", _) // which one to choose? 

consideran que no es sólo usted quien puede hacer val m1 = hello("aaa", _). Podría haber un usuario de su clase, haciendo val my_hello = (new C).hello("aaa", _). Y luego rompes la compatibilidad del código fuente al agregar una sobrecarga al método original de la cadena hello porque de repente ya no está claro qué se debe hacer.

No estoy seguro de que esta sea la única razón, pero ciertamente se puede ver como una medida de seguridad.

+0

pero en mi código, solo hay un método 'hello'. ¿Quiere decir que la clase puede extenderse y la subclase puede anular el método 'hello' y romper el código? – Freewind

+0

Debo admitir que no estoy seguro de si esto es realmente posible con la creación de subclases. Pero incluso sin él, creo que hace que sea un poco más consistente para requerir siempre la anotación de tipo. De lo contrario, todo el código sin una anotación de tipo que se rompería de repente, si elige agregar una sobrecarga. – Debilski

+0

Tengo curiosidad de por qué, en ese caso, 'm1' no es solo polimórfico sobre el tipo de argumento. –

4

En pocas palabras, Scala usa los tipos de parámetros para buscar el método apropiado, no el tipo de método para deducir el tipo de los parámetros.

Para hacer lo que quiera, debería buscar todas las llamadas posibles al hello con dos parámetros, el primero de ellos String - que podría incluir conversiones implícitas - y luego, si se encuentra una opción más específica , úsala para inferir el tipo de ese segundo parámetro. Tendría que hacer esto además a todo lo que hace ya, ralentizando aún más lo que ya es una compilación bastante lenta. No es imposible, pero no hace eso.

Cuestiones relacionadas