for
comprehensions in Scala are just syntactic sugar. These comprehensions are implemented using the withFilter
, foreach
, flatMap
and map
methods of their subject types. For this reason, only types that have these methods defined can be utilized in a for
comprehension.
A for
comprehension of the following form, with patterns pN
, generators gN
and conditions cN
:
for(p0 <- x0 if g0; p1 <- g1 if c1) { ??? }
... will de-sugar to nested calls using withFilter
and foreach
:
g0.withFilter({ case p0 => c0 case _ => false }).foreach({
case p0 => g1.withFilter({ case p1 => c1 case _ => false }).foreach({
case p1 => ???
})
})
Whereas a for
/yield
expression of the following form:
for(p0 <- g0 if c0; p1 <- g1 if c1) yield ???
... will de-sugar to nested calls using withFilter
and either flatMap
or map
:
g0.withFilter({ case p0 => c0 case _ => false }).flatMap({
case p0 => g1.withFilter({ case p1 => c1 case _ => false }).map({
case p1 => ???
})
})
(Note that map
is used in the innermost comprehension, and flatMap
is used in every outer comprehension.)
A for
comprehension can be applied to any type implementing the methods required by the de-sugared representation. There are no restrictions on the return types of these methods, so long as they are composable.