[toc]
This appendix for my book, Functional Programming, Simplified (Scala edition), consists of examples of how different Scala 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.)
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)
foreach
The Scala compiler translates this for expression:
for {
x <- xs
} println(x)
into this code:
xs.foreach(x => println(x))
Notes
for/printlntranslates toforeach
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/yieldtranslates tomap
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/yieldbecomesflatMap/map
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/yieldbecomesflatMap/map. It doesn’t matter if they class in theforexpression is aListor anOption.
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/yieldbecomesflatMap/flatMap/map
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
withFilteris called beforemap
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
iftranslates towithFilter(at the appropriate place)
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
}
}
}
}
| this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |
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.