0Pricing
Scala for Backend Engineering & Functional Programming · Lección

Desazucarado de for

map y flatMap

Desazucarado de for es una lección gratuita de Scala for Backend Engineering & Functional Programming en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Scala for Backend Engineering & Functional Programming, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Scala for Backend Engineering & Functional Programming incluye 4 lecciones en total.

¿Qué es una for-comprehension?

Una for-comprehension en Scala es una sintaxis especial para trabajar con colecciones y otros tipos contenedores. Parece un bucle imperativo, pero en realidad es azúcar sintáctico que el compilador reescribe como llamadas a map, flatMap, filter y foreach.

Entender el desazucarado le ayuda a razonar sobre cualquier for-comprehension, incluso con tipos personalizados.

object Main {
  def main(args: Array[String]): Unit = {
    val result = for (x <- List(1, 2, 3)) yield x * 10
    println(result)
  }
}

Un solo generador se convierte en map

Cuando una for-comprehension tiene exactamente un generador y usa yield, el compilador la reescribe como una única llamada a map.

  • for (x <- xs) yield f(x)
  • se convierte en xs.map(x => f(x))
object Main {
  def main(args: Array[String]): Unit = {
    val a = for (x <- List(1, 2, 3)) yield x + 1
    val b = List(1, 2, 3).map(x => x + 1)
    println(a == b)
  }
}

La palabra clave yield

La palabra clave yield indica a Scala que debe recopilar los resultados en una nueva colección del mismo tipo.

Sin yield, la for-comprehension ejecuta un efecto secundario para cada elemento y devuelve Unit (se convierte en foreach).

object Main {
  def main(args: Array[String]): Unit = {
    // No yield: side effect only
    for (x <- List("a", "b")) println(x)
    // With yield: builds a new List
    val upper = for (x <- List("a", "b")) yield x.toUpperCase
    println(upper)
  }
}

Dos generadores se convierten en flatMap + map

Con dos o más generadores, los externos se convierten en flatMap y el más interno en map.

  • for (x <- xs; y <- ys) yield f(x, y)
  • se convierte en xs.flatMap(x => ys.map(y => f(x, y)))
object Main {
  def main(args: Array[String]): Unit = {
    val pairs = for {
      x <- List(1, 2)
      y <- List("a", "b")
    } yield (x, y)
    println(pairs)
  }
}

Ver el flatMap equivalente

Aquí escribimos la misma lógica de las dos formas. Demostrar que son equivalentes muestra que las for-comprehensions no añaden magia, sino legibilidad.

object Main {
  def main(args: Array[String]): Unit = {
    val sugar = for {
      x <- List(1, 2)
      y <- List(10, 20)
    } yield x + y

    val desugared = List(1, 2).flatMap(x => List(10, 20).map(y => x + y))

    println(sugar)
    println(sugar == desugared)
  }
}

Por qué flatMap para el generador externo

Cada elemento externo produce una colección completa de resultados internos. Si usáramos map para el generador externo, obtendríamos una colección anidada, como List(List(...), List(...)).

flatMap aplana esas listas anidadas en un único resultado plano.

object Main {
  def main(args: Array[String]): Unit = {
    val nested = List(1, 2).map(x => List(10, 20).map(y => x + y))
    val flat   = List(1, 2).flatMap(x => List(10, 20).map(y => x + y))
    println(nested)
    println(flat)
  }
}

for sin yield es foreach

Un bucle for sin yield se reescribe como foreach. Ejecuta el cuerpo para producir sus efectos secundarios y devuelve Unit.

  • for (x <- xs) doSomething(x)
  • se convierte en xs.foreach(x => doSomething(x))
object Main {
  def main(args: Array[String]): Unit = {
    val r: Unit = for (x <- List(1, 2, 3)) print(x + " ")
    println()
    println("Return type is Unit")
  }
}

El tipo del resultado sigue al primer generador

El tipo del resultado viene determinado por la colección del primer generador. Un for sobre un List produce un List; sobre un Set, un Set; sobre una Option, una Option.

object Main {
  def main(args: Array[String]): Unit = {
    val fromList = for (x <- List(1, 2, 2, 3)) yield x
    val fromSet  = for (x <- Set(1, 2, 2, 3)) yield x
    println(fromList)
    println(fromSet)
  }
}

Vincular valores con =

Dentro de una for-comprehension puede vincular valores intermedios con =. Esto evita recalcularlos y mejora la legibilidad.

Se desazucara como un map que transporta el valor adicional dentro de una tupla.

object Main {
  def main(args: Array[String]): Unit = {
    val result = for {
      x <- List(1, 2, 3)
      doubled = x * 2
    } yield doubled + 1
    println(result)
  }
}

Funciona con cualquier tipo que tenga map/flatMap

Como el desazucarado solo depende de map y flatMap, las for-comprehensions funcionan con cualquier tipo que defina esos métodos: Option, Either, Try, Future y sus propias clases.

object Main {
  def main(args: Array[String]): Unit = {
    val combined = for {
      a <- Some(2)
      b <- Some(3)
    } yield a * b
    println(combined)
  }
}

La verdadera ventaja es la legibilidad

Compare una cadena profundamente anidada de flatMap/map con una for-comprehension clara. Se compilan en lo mismo, pero la versión con for se lee de arriba abajo como una receta.

object Main {
  def main(args: Array[String]): Unit = {
    val chained = List(1, 2).flatMap(a => List(3, 4).map(b => a * b))
    val readable = for {
      a <- List(1, 2)
      b <- List(3, 4)
    } yield a * b
    println(chained == readable)
  }
}

Comprobación rápida

¿Cómo desazucara el compilador una for-comprehension con dos generadores y un yield?

Resumen

Ha aprendido cómo se desazucaran las for-comprehensions:

  • Un generador + yield → map
  • Varios generadores + yield → flatMap (externo) + map (interno)
  • Sin yield → foreach, que devuelve Unit
  • Las vinculaciones val = añaden valores intermedios
  • El tipo del resultado sigue al primer generador

Cualquier tipo con map y flatMap puede usarse en una for-comprehension.

Preguntas frecuentes

¿La lección «Desazucarado de for» es gratis?

Sí — el texto completo de «Desazucarado de for» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Scala for Backend Engineering & Functional Programming, actualiza a CoddyKit PRO. El curso de Scala for Backend Engineering & Functional Programming incluye 4 lecciones en total.

¿Qué aprenderé en «Desazucarado de for»?

map y flatMap Practicas Scala for Backend Engineering & Functional Programming con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Scala for Backend Engineering & Functional Programming?

No se requiere experiencia previa. Scala for Backend Engineering & Functional Programming en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.

¿Cuánto tiempo toma la lección «Desazucarado de for»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Scala for Backend Engineering & Functional Programming?

Sí. Cada lección de Scala for Backend Engineering & Functional Programming incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Desazucarado de for
  2. Filtrado con if
  3. Varios generadores
  4. Uso con Option y Future
← Volver a Scala for Backend Engineering & Functional Programming