for scala list-comprehension

for - Las comprensiones de Scala: ¿característica vital o azúcar sintáctica?



for yield scala (5)

Cuando empecé a mirar a Scala, me gustó el aspecto de las comprensiones. Parecían ser un poco como los bucles foreach a los que estaba acostumbrado desde Java 5, pero con restricciones funcionales y mucha dulzura sintáctica.

Pero a medida que he absorbido el estilo de Scala, encuentro que cada vez que puedo usar un for-comprension, estoy usando map , flatMap , filter , reduce y foreach lugar. La intención del código me parece más clara de esa manera, con menos posibles sorpresas ocultas, y también suelen ser códigos más cortos.

Por lo que yo sé, las comprensiones siempre se compilan en estos métodos de todos modos, así que me pregunto: ¿para qué sirven realmente? ¿Me estoy perdiendo algo de revalorización funcional (no sería la primera vez)? ¿Las comprensiones hacen algo que las otras características no pueden, o al menos serían mucho más torpes? ¿Brillan bajo un caso de uso particular? ¿Es realmente una cuestión de gusto personal?


En algunos casos, las comprensiones pueden expresar mejor la intención, de modo que cuando lo hacen, utilícelas.

También tenga en cuenta que con las comprensiones, obtendrá la coincidencia de patrones de forma gratuita. Por ejemplo, iterar sobre un mapa es mucho más sencillo con la comprensión:

for ((key, value) <- map) println (key + "-->" + value)

que con foreach:

map foreach { case (key, value) => println (key + "-->" + value) }


Las comprensiones son azúcar sintáctica, pero eso no significa que no sean vitales. Usualmente son más concisos que su forma expandida, lo cual es bueno, pero quizás lo más importante es que ayudan a los programadores de lenguajes imperativos a usar construcciones funcionales.

Cuando empecé con Scala, utilicé muchas comprensiones porque eran familiares. Luego casi me detuve por completo, porque sentía que el uso de los métodos subyacentes era más explícito y, por lo tanto, más claro. Ahora vuelvo a usar las comprensiones porque creo que es mejor que expresen la intención de lo que estoy haciendo en lugar de los medios para hacerlo.


Otro gran uso de la comprensión es para DSL interno. ScalaQL es un gran ejemplo de esto. Puede convertir esto

val underAge = for { p <- Person c <- Company if p.company is c if p.age < 14 } yield p

dentro de esto

SELECT p.* FROM people p JOIN companies c ON p.company_id = c.id WHERE p.age < 14

Y mucho más.


Por favor refiérase a esta pregunta . La respuesta corta es que las comprensiones pueden ser más legibles. En particular, si tiene muchos generadores anidados, el alcance real de lo que está haciendo se vuelve más claro y no necesita grandes sangrías.


Tienes razón. La comprensión es el azúcar sintáctico. Creo que los métodos subyacentes son más sucintos y fáciles de leer, una vez que estás acostumbrado a ellos.

Compara las siguientes declaraciones equivalentes:

1. for (i <- 1 to 100; if (i % 3 == 0)) yield Math.pow(i, 2) 2. (1 to 100).filter(_ % 3 == 0).map(Math.pow(_, 2))

En mi opinión, la adición del punto y coma en el # 1 distrae de la sensación de que se trata de una declaración encadenada única. También existe la sensación de que i es una var (¿es 1, o es 99, o algo intermedio?) Que resta valor a un estilo funcional.

La opción 2 es más evidentemente una cadena de llamadas de método a objetos. Cada eslabón en la cadena declara claramente su responsabilidad. No hay variables intermedias.

Tal vez para la comprensión se incluyen como una conveniencia para los desarrolladores que hacen la transición desde Java. Independientemente, lo que se elija es una cuestión de estilo y preferencia.