Appendix: Scala `for` expression translation examples

This is a page from my book, Functional Programming, Simplified

This appendix consists of examples of how different for expressions translate to map and flatMap function calls. A few examples also show foreach and withFilter. (I don’t include a thorough discussion of each translation, I just show my initial code and how it’s translated by the Scala compiler.)

Back to top

Sample lists

The examples that follow assume that three List variables named xs, ys, and zs exist, such as these:

val xs = List(1,2,3)
val ys = List(4,5,6)
val zs = List(7,8,9)
Back to top

foreach

The Scala compiler translates this for expression:

for {
    x <- xs
} println(x)

into this code:

xs.foreach(x => println(x))

Notes

  • for/println translates to foreach
Back to top

for/yield with one generator

This for expression:

val a = for {
    x <- xs
} yield x 

translates to this code:

val a = xs.map(x => x)

Notes

  • a single generator in for/yield translates to map
Back to top

for/yield with two generators

This for expression:

val a = for {
    x <- xs
    y <- ys
} yield x + y

translates to this code:

val a = xs.flatMap { x => 
    ys.map(y => x + y)
}

Notes

  • two generators in for/yield becomes flatMap/map
Back to top

for/yield with two Option generators

This for expression:

val x = for {
    i <- Option(1)
    j <- Option(2)
} yield i * j

translates to this code:

val x = Option(1).flatMap { i => 
    Option(2).map { j => 
        i * j
    }
}

Notes

  • as in the previous example, two generators in for/yield becomes flatMap/map. It doesn’t matter if they class in the for expression is a List or an Option.
Back to top

for/yield with three generators

This for expression:

val a = for {
    x <- xs
    y <- ys
    z <- zs
} yield x + y + z

translates to this code:

val a = xs.flatMap { x => 
    ys.flatMap { y => 
        zs.map { z => 
            x + y + z
        }
    }
}

Notice that what I show in the translated code as x + y + z is a simplification of what really happens. When scalac compiles the code, it really looks like this:

zs.map(((z) => x.$plus(y).$plus(z)))

I mention this now because you’ll see it in some of the examples that follow.

Notes

  • three generators in for/yield becomes flatMap/flatMap/map
Back to top

A filter in a for expression

This for expression:

val a = for {
    x <- xs
    if x < 2   //filter
} yield x

translates to this code:

val a = xs.withFilter(x => x < 2)
          .map(x => x)

Notes

  • 'if' translates to withFilter
  • notice that withFilter is called before map
Back to top

A filter in a longer for expression

This for expression:

val a = for {
    x <- xs
    if x > 2    //filter
    y <- ys
    z <- zs
} yield x + y + z

translates to this code:

val a = xs.withFilter { x => 
    x.$greater(2).flatMap { x => 
        ys.flatMap { y => 
            zs.map { z => 
                x.$plus(y).$plus(z)
            }
        }
    }
}

Notes

  • if translates to withFilter (at the appropriate place)
Back to top

A block of code after yield

This for expression:

val a = for {
    x <- xs
    if x > 2    //filter
    y <- ys
    z <- zs
} yield {
    val b = x + y
    val c = b * z
    c
}

translates to this code:

val a = xs.withFilter { x => 
    x.$greater(2).flatMap { x => 
        ys.flatMap { y => 
            zs.map { z =>
                val b = x.$plus(y)
                val c = b.$times(z)
                c
            }
        }
    }
}

Notes

I created this example to show that (a) you can use a block of code after yield, and (b) how that code is translated by the compiler into an anonymous function inside map.

Back to top

books i’ve written