scala - tecnicas - tipos de subrayado pdf
¿Cuáles son las reglas para gobernar el subrayado para definir la función anónima? (2)
Estoy usando _
como marcador de posición para crear una función anónima, y el problema es que no puedo predecir cómo Scala va a transformar mi código. Más precisamente, determina erróneamente qué tan "grande" es la función anónima que quiero.
List(1,2,3) foreach println(_:Int) //error !
List(1,2,3) foreach (println(_:Int)) //work
List(1,2,3) foreach(println(_:Int)) //work
Usando -Xprint:typer
Puedo ver que Scala transforma el primero en "una gran función anónima":
x$1 => List(1,2,3) foreach(println(x$1:Int))
el 2 ° 3 ° trabajado es la transformación correcta en lo que quiero.
... foreach (x$1 => println(x$1:Int))
¿Por qué esto? Cual es la regla ?
Creo que la respuesta del Sr. Sobral es incorrecta. Las reglas reales se pueden encontrar en Scala Language Reference , sección 6.23, subtítulo "Sintaxis del marcador de posición para funciones anónimas".
La única regla es que la expresión más interna que contiene correctamente el guión bajo define el alcance de la función anónima. Eso significa que las dos primeras reglas del Sr. Sobral son correctas, porque una llamada a un método es una expresión y la expresión entre paréntesis no cambia su significado. Pero la tercera regla es lo opuesto a la verdad: si todas las demás cosas son iguales, se usará la expresión más pequeña que tenga sentido.
Desafortunadamente, mi explicación del comportamiento que el Sr. Laskowski observó para su primer ejemplo es un poco complicado y especulativo. Cuando
List(1,2,3) foreach println(_:Int)
está escrito en el bucle Scala read-eval-print. El mensaje de error es:
error: type mismatch;
found : Unit
required: Int => ?
List(1,2,3) foreach println(_:Int)
^
Si modifica el ejemplo un poquito:
List(1,2,3).foreach println(_:Int)
el mensaje de error es más fácil de entender:
error: missing arguments for method foreach in class List;
follow this method with `_'' if you want to treat it as a partially applied function
List(1,2,3).foreach println(_:Int)
^
Para entender un poco mejor las cosas, llame a scala
manera: scala -Xprint:parser
, que, después de que cada expresión sea tipeada por el usuario, hace que la expresión sea cargada por el analizador para ser impresa. (Junto con una gran cantidad de basura, que voy a omitir.) Para el primer ejemplo de Laskowski, la expresión que entiende el analizador es
((x$1: Int) => List(1, 2, 3).foreach(println((x$1: Int))))
Para el segundo ejemplo, la versión del analizador es
((x$1: Int) => List(1, 2, 3).foreach.println((x$1: Int)))
Aparentemente, la regla de alcance se aplica antes de que la estructura de expresiones se haya desarrollado completamente. En ambos casos, el analizador adivina que la expresión más pequeña comienza en Lista, aunque una vez que se insertan los parens, ya no es verdadera. En el segundo ejemplo, además de esa suposición, asume que, como println
es un identificador, foreach println
es una cadena de métodos, el primero no tiene argumentos. El error en foreach
se println
antes del error en println
, enmascarándolo. El error en println
es que su resultado es Unidad, y foreach
requiere una función. Una vez que ve el árbol de análisis sintáctico, es fácil ver que esto es correcto, pero no está claro (para mí) por qué el árbol de análisis sintáctico es lo que es.
Reglas simples para determinar el alcance del guión bajo:
- Si el guión bajo es un argumento para un método, entonces el alcance estará fuera de ese método, de lo contrario las reglas a continuación;
- Si el guión bajo está dentro de una expresión delimitada por () o {}, se usará el delimitador más interno que contenga el guión bajo;
- En igualdad de condiciones, se usará la expresión más grande posible.
Entonces, según la regla # 1, en lugar de println((x: Int) => x)
, el alcance se colocará fuera (incluido) println
.
Por regla # 2, los dos últimos ejemplos tendrán la función delimitada por paréntesis, entonces (x => println(x: Int))
.
Según la regla n. ° 3, el primer ejemplo será la expresión completa, ya que no hay paréntesis delimitadores.