Scala for comprehension translation helper
“For comprehension” is a another syntaxe to use map
, flatMap
and withFilter
(or filter) methods.
yield
keyword is used to aggregate values in the resulting structure.
This composition can be used on any “monadic” type implementing this methods, like List
, Option
, Future
, etc.
Case 1
case class Book(author: String, title: String)
for {
book <- books
if book.author startsWith "bob"
} yield book.title
is the same as
books.withFilter(book => book.author startsWith "bob").map(book => book.title)
Case 2
case class Book(authors: List[String], title: String)
for {
book <- books
author <- book.authors
if author startsWith "bob"
} yield book.title
is the same as
books.flatMap(book => book.authors.withFilter(author => author startsWith "bob").map(author => book.title))
Case 3
val optA : Option[String] = Some("a value")
val optB : Option[String] = Some("b value")
I want an option tuple : Option[(String, String) composing this two options, i.e. Some(("a value","b value"))
:
for {
a <- optA
b <- optB
} yield (a,b)
is the same as
optA.flatMap(a => optB.map(b => (a, b)))
You can also filter options with if/withFilter :
for {
a <- optA
if(a startsWith "a")
b <- optB
} yield (a,b)
Or
optA.withFilter(a=> a startsWith "a").flatMap(a => optB.map(b => (a, b)))
If you change “a” to “c” in the condition, the resulting value will be None
instead of Some(("a value","b value"))
.
Case 4
You can mix options and list types in map/flatMap (Option can be seen as a simple collection) :
val optNumbers = List(Some(1), Some(2), None, Some(3))
We want to remove empty values and increment other values : List(2, 3, 4)
:
for {
optNumber <- optNumbers
value <- optNumber
} yield value +1
is the same as
optNumbers.flatMap(optNumber => optNumber.map(value => value+1))