comprehension - Scala "<-" para comprensión
for yield scala (3)
He descubierto que Scala siempre tiene una "explicación natural" para cualquier cosa. Siempre algo como "ohh, pero eso es solo una función que se llama en este y ese objeto con este y ese parámetro". En cierto sentido, nada es realmente compilador, como lo conocemos desde otros idiomas.
Mi pregunta es sobre el operador <- como se usa en el siguiente código:
for(i <- 0 to 10) println(i)
En este ejemplo, puedo ver que se reescribe a algo así como:
0.to(10).foreach((i:Int)=>println(i))
pero esto no explica cómo fui llevado a la función anónima dentro de la función foreach. En el punto donde escribes i, no es un objeto, y aún no es una variable declarada. Entonces, ¿qué es y cómo se transmite al interior de Foreach?
Creo que finalmente descubrí algo que, de hecho, es magia de compilación
Gracias por tu tiempo.
Para aclarar, mi pregunta es: ¿cómo funciona el operador <- en la primera línea de código ya que no es un objeto sobre el que se puede llamar como una función.
En este caso, realmente es un poco de magia de compilación. La traducción de for-comprehension a filter / map / flatmap form es un proceso especial de desugaring, muy parecido a la conversión de las formas especiales de actualización y aplicación de métodos.
Para aumentar la respuesta de Dave, aquí hay un esquema de traducción para ''for-comprehensions'' de la especificación del lenguaje Scala:
Una comprensión
for (enums) yield e
evalúa la expresióne
para cada enlace generado por los enumeradores enumerados. Una secuencia de enumerador siempre comienza con un generador; esto puede ser seguido por generadores adicionales, definiciones de valores o guardias.Un generador
p <- e
produce enlaces a partir de una expresióne
que coincide de alguna manera con el patrónp
. Una definición de valorval p = e
vincula el nombre de valorp
(o varios nombres en un patrónp
) al resultado de evaluar la expresióne
. Un guardiánif e
contiene una expresión booleana que restringe los enlaces enumerados.El significado preciso de generadores y guardias se define mediante la traducción a invocaciones de cuatro métodos:
map
,filter
,flatMap
yforeach
. Estos métodos se pueden implementar de diferentes maneras para diferentes tipos de operadores.El esquema de traducción es el siguiente. En un primer paso, cada generador
p <- e
, donde p no es irrefutable (§8.1) para el tipo dee
se reemplaza por
p <- e.filter { case p => true; case _ => false }
Luego, las siguientes reglas se aplican repetidamente hasta que se hayan eliminado todas las comprensiones.
Una for-comprensión
for (p <- e) yield e0
se traduce ae.map { case p => e0 }
.Una for-comprensión
for (p <- e) e0
se traduce ae.foreach { case p => e0 }
.Una for-comprensión
for (p <- e; p0 <- e0 . . .) yield e00
, donde. . . es una secuencia (posiblemente vacía) de generadores o guardias, se traduce a:
e.flatMap { case p => for (p0 <- e0 . . .) yield e00 }
.A for-understanding
for (p <- e; p0 <- e0 . . .) e00
donde. . . es una secuencia (posiblemente vacía) de generadores o guardias, se traduce a:
e.foreach { case p => for (p0 <- e0 . . .) e00 }
.Un generador
p <- e
seguido de un guardiaif g
se traduce a un solo generador:
p <- e.filter((x1, . . . , xn) => g )
dondex1
. . ,xn
son las variables libres dep
.Un generador
p <- e
seguido de una definición de valorval p0 = e0
se traduce al siguiente generador de pares de valores, dondex
yx0
son nombres nuevos:
val (p, p0) <- for(x@p <- e) yield { val x0@p0 = e0; (x, x0) }
<-
es un símbolo de palabra clave definido por el idioma, como is =>
pero en claro contraste con ->
(que es un símbolo definido). Debido a que es parte de la gramática básica de Scala, se puede usar para crear enlaces (para el i
en su ejemplo) que es algo que no se puede hacer mediante construcciones definidas por el usuario.