for (x <- expr1 if expr2; seq) yield expr3
is translated to:
for (x <- expr1 withFilter expr2; seq) yield expr3
Then translation continues with the second expression, which is again shorter by one element than the original one.
Translating for expressions starting with two generators
The next case handles for expressions that start with two generators, as in:
for (x <- expr1; y <- expr2; seq) yield expr3
Again, assume that seq is an arbitrary sequence of generators, definitions and filters. In fact, seq might also be empty, and in that case there would not be a semicolon after expr2. The translation scheme stays the same in each case. The for expression above is translated to an application of flatMap:
expr1.flatMap(x => for (y <- expr2; seq) yield expr3)
This time, there is another for expression in the function value passed to flatMap. That for expression (which is again simpler by one element than the original) is in turn translated with the same rules.
The three translation schemes given so far are sufficient to translate all for expressions that contain just generators and filters, and where generators bind only simple variables. Take for instance the query, “find all authors who have published at least two books,” from Section 23.3:
for (b1 <- books; b2 <- books if b1 != b2;
a1 <- b1.authors; a2 <- b2.authors if a1 == a2) yield a1
This query translates to the following map/flatMap/filter combination:
books flatMap (b1 =>
books withFilter (b2 => b1 != b2) flatMap (b2 => b1.authors flatMap (a1 =>
b2.authors withFilter (a2 => a1 == a2) map (a2 => a1))))