for ( i <- 1 to n) println(i)
// i iterates through all values in 1 to n
for {
i <- 1 to 9
j <- 1 to 9
} println(s"($i,$j)")
// Multiple iterates
for {
i <- 1 to 9
j <- 1 to 9 if i != j
} println(s"($i,$j)")
// Guards
for {
i <- 1 to 3
from = 4 - i
j <- from to 3
} println(s"($i,$j)")
// Variables
val r = for (i <- 1 to n) yield i*i
// r will be a sequence 1, 4, 9, 25, ...
for ( (x,y) <- pairs) println( x + "" y)
// Destructures pairs with extractors
A for-comprehension is syntactic sugar for map
, flatMap
and filter
operations on collections.
The general form is for (s) yield e
s
is a sequence of generators and filtersp <- e
is a generatorif f
is a filter{ s }
instead of ( s )
if you want to use multiple lines without requiring semicolonse
is an element of the resulting collectiond = p
is a definition // list all combinations of numbers x and y where x is drawn from
// 1 to M and y is drawn from 1 to N
for (x <- 1 to M; y <- 1 to N)
yield (x,y)
is equivalent to
(1 to M) flatMap (x => (1 to N) map (y => (x, y)))
A for-expression looks like a traditional for loop but works differently internally
for (x <- e1) yield e2
is translated to e1.map(x => e2)
for (x <- e1 if f) yield e2
is translated to for (x <- e1.filter(x => f)) yield e2
for (x <- e1; y <- e2) yield e3
is translated to e1.flatMap(x => for (y <- e2) yield e3)
This means you can use a for-comprehension for your own type, as long
as you define map
, flatMap
and filter
.
For more, see lecture 6.5.
for {
i <- 1 until n
j <- 1 until i
if isPrime(i + j)
} yield (i, j)
is equivalent to
for (i <- 1 until n; j <- 1 until i if isPrime(i + j))
yield (i, j)
is equivalent to
(1 until n).flatMap(i => (1 until i).filter(j => isPrime(i + j)).map(j => (i, j)))
For a class to be used in a for comprehension it needs to have the following methods defined:
abstract class CustomClass[T] {
def map[U](f: T => U): CustomClass[U]
def flatMap[U](f: T => CustomClass[U]): CustomClass[U]
def withFilter(p: T => Boolean): CustomClass[T]
}
Whenever a generic class has map, flatMap, and withFilter defined on it (with the signatures as above) then it can be used inside a for comprehension.