Comprehensions

Esta es la trigésima parada en el Tour de Ceylon. En el sección anterior hemos visto como invocar funciones usando argumentos con nombre. Ahora estamos listos para aprender acerca de comprehensions.

Comprehensions

Un comprenhension es una forma conveniente para transformar, filtrar o combinar un flujo o flujos de valores antes de pasarle el resultado a la función. Comprehensions actúan sobre ello y producen instancias de Iterable. Un comprehension puede aparecer en:

  • dentro de corchetes, produciendo una secuencia.
  • dentro de llaves, produciendo iterables, o
  • dentro de una lista de argumentos con nombre.

La sintaxis para instanciar una secuencia, que conocimos anteriormente esta considerada para tener un parámetro de tipo iterable, así podemos usar comprehension para construir una secuencia:

String[] name = [ for (p in people) p.name ];

¡Pero conprehension no son solo útiles para construir secuencias! Supongamos que tenemos una clase HashMap, con la siguiente forma.

class HashMap<Key,Item>({Key->Item*} entries) { ... }

Entonces podemos construir un HashMap<String,Person> como en lo siguiente:

value peopleByName = HashMap { for (p in people) p.name->p };

Como ya has podido suponer,la clausula for de comprehension funciona un poco como el ciclo for que vimos anteriormente. El toma cada elemento de el flujo Iterable en turno. Pero esto lo hace lazily, cuando la función de recepción actualmente itera su argumento.

Esto significa que si la función de recepción no necesita iterar el flujo completo, el comprehension nunca sera totalmente evaluado. Esto es extremamente útil para funciones como every() y any():

if (every { for (p in people) p.age>=18 }) { ... }

La función every() (en ceylon.language)acepta un flujo de valores booleanos, y detiene su iteración tan pronto como encuentre false en el flujo.

Si necesitamos almacenar el flujo de valores en algún lugar, sin evaluar ninguno de sus elementos, podemos usar una expresión para construir iterables, como este:

{String*} names = { for (p in people) p.name };

Ahora veamos lo que los varios tipos de comprehension hacen.

Transformación

La primer cosa que podemos hacer con un comprehension es transformar los elementos del flujo usando una expresión para producir un nuevo valor para cada elemento. Esta expresión aparece al final de un comprehension. Esta es la cosa que el Iterable resultante en realidad itera.

Por ejemplo, esta comprehension

for (p in people) p.name->p

resulta en un Iterable<String->Person>. Para cada elemento de people una nueva Entry<String,Person> es construida por el operador ->.

Filtrado

La clausula if de comprehension nos permite evitar ciertos valores de el flujo. Esta Comprehension produce un flujo de números que son divisibles por 3.

for (i in 0..100) if (i%3==0) i

Esto es especialmente útil para filtrar usando if (exists ...).

for (p in people) if (exists s=p.spouse) p->s

Puedes usar incluso múltiples condiciones de if:

for (p in people)
    if (exists s=p.spouse,
        nonempty inlaws=s.parents)
            p->inlaws

Productos y uniones

Un comprehension puede tener mas que una clausula for. Esto nos permite combinar dos flujos para obtener un flujo de valores de su producto cartesiano:

for (i in 0.100) for (j in 0..100) Node(i,j)

Incluso mas útil, nos permite obtener un flujo de valores asociados, como en un join de SQL.

for (o in orgs) for (e in o.employees) e.name

Aún hay más

Después vamos a discutir algunos de los tipos básicos que hay en el modulo del lenguaje, en particular tipos numéricos e introducir la idea del polimorfismo de operadores.

Puedes leer mas acerca de trabar con objetos iterables en Ceylon en este blog.