"For comprehension" is a another syntax 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 type implementing this methods, like List
, Option
, Future
...
Install jad:
brew install homebrew/binary/jad
-
Compile the code:
scalac -d out Forcomptran.scala
-
To see the decompiled code, run (for example, Case1):
jad -lnc -p -t 2 -v ./out/Case1\$.class
case class Book(author: String, title: String)
for {
book <- books if book.author startsWith "Ivan"
} yield book.title
is the same as:
books.withFilter(book => book.author startsWith "Ivan")
.map(book => book.title)
case class Book(author: String, title: String)
for { book <- books
author = book.author.replaceAll("\\s+", "_").toLowerCase
if author startsWith "ivan"
} yield s"$author: ${book.title}"
is the same as:
books
.map(book => (book, book.author.replaceAll("\\s+", "_").toLowerCase)) // Tuple2(book, author)
.withFilter(_._2 startsWith "ivan")
.map { case (book, author) => s"$author: ${book.title}" }
case class Book(authors: List[String], title: String)
for {
book <- books
author <- book.authors if author contains "er"
} yield book.title
is the same as:
books.flatMap(book =>
book.authors.withFilter(author => author contains "er")
.map(author => book.title))
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 {
/* 1 */ a <- optA
/* 2 */ if a startsWith "a"
/* 3 */ b <- optB
} yield (a,b)
Or:
/* 2 */ optA.withFilter(a => a startsWith "a")
/* 1 */ .flatMap(a =>
/* 3 */ 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"))
.
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))