For comprehension and importance of beauty

There are many existential questions in the modern world we live in. But there is one question that surpasses them all. What does a for comprehension really do?

The answer to this intricate matter is… nothing new. For comprehension structures are just syntactic sugar. Underneath, and depending on how the block is built, there will be calls to map, flatMap, withFilter or foreach.

For comprehension structures will have two key parts:

  • The for block, by which nested queries are performed
  • The yield block, where previous queries are grouped and treated

In order to understand these concepts, let’s take a look at a small example:

for {
  x <- List(1, 2, 3)
  y <- List(true, false) 
} yield (x, y)

The result of this expression is the combination in tuples of the first list with the second:

  (1, true),
  (1, false),
  (2, true),
  (2, false),
  (3, true),
  (3, false)

What this for comprehension is really doing is performing the following operations:

List(1, 2, 3).flatMap(x =>
  List(true, false).map( y => (x, y))

As can be seen, with for blocks everything becomes much more readable. All that needs to be done is to join several flatMaps to conclude with a map. Let’s see another example:

for {
  x <- List(1, 2)
  y <- List(true, false)
  z <- List("a", "b") 
} yield (x, y, z)

which is equivalent to:

List(1, 2, 3).flatMap(x =>
  List(true, false).flatMap( y =>
    List("a", "b").map(z => (x, y, z))

and the result produced is:

  (1, true, "a"),
  (1, true, "b"),
  (1, false, "a"),
  (1, false, "b"),
  (2, true, "a"),
  (2, true, "b"),
  (2, false, "a"),
  (2, false, "b")

Moreover, we can also apply filters by using embedded if statements:

for {
  x <- List(1, 2, 3, 4, 5, 6, 7)
  if x < 3
  y <- List("a", "b") 
} yield (x, y)

//result: List((1,a), (1,b), (2,a), (2,b))

whose equivalent is:

List(1, 2, 3, 4, 5, 6, 7)
  .withFilter(_ < 3)
  .flatMap( x =>
    List("a", "b").map(
      y => (x, y)

It may happen that not only we want to create a new collection, but also we want some operations to be applied to each one of the elements. In such a situation, we will not use the yield block. This will change the translation as we don’t want to make changes to a collection and thus, instead of being a map method, it will be the foreach method. This makes perfect sense since, in this case, we only want to perform actions for each generated event and the type of the final result will be Unit.

for {
  x <- List(1, 2, 3)
  y <- List(true, false)
} println(s"($x , $y)") 

List(1, 2, 3).foreach(x =>
  List(true, false).foreach( y =>
    println(s"($x , $y)")

After all these examples, we hope that you use the for comprehension to make your code more readable whenever possible. Although we all know that the magic lies within.



One thought on “For comprehension and importance of beauty


Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de

Estás comentando usando tu cuenta de Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s