for comprehension is a syntax shortcut to combine
flatMap and map in a way that's easy to read and reason about.
Let's simplify things a bit and assume that every class that provides both aforementioned methods can be called a monad and we'll use the symbol M[A] to mean a monad with an inner type A.
Some commonly seen monads
Future[String => Boolean]where
A: String => Boolean
Defined in a generic monad
1. Each line in the expression using the
<- symbol is translated to a
flatMap call, except for the last line which is translated to a concluding
map call, where the "bound symbol" on the left-hand side is passed as the parameter to the argument function (what we previously called
f: A => M[B]):
2. A for-expression with only one
<- is converted to a
map call with the expression passed as argument:
As you can see, the
map operation preserves the "shape" of the original
monad, so the same happens for the
yield expression: a
List remains a
List with the content transformed by the operation in the
On the other hand each binding line in the
for is just a composition of successive
monads, which must be "flattened" in order to maintain a single "external shape".
Suppose for a moment that each internal binding was translated to a
map call, but the right-hand was the same
A => M[B] function, you would end up with a
M[M[B]] for each line in the comprehension.
The intent of the whole for syntax is to easily "flatten" the concatenation of successive monadic operations (i.e. operations that "lift" a value in a "monadic shape":
A => M[B]), with the addition of a final map operation that possibly performs a concluding transformation.
I hope this explains the logic behind the choice of translation, which is applied in a mechanical way, that is:
flatMap nested calls concluded by a single
As already said, the shape of the monad is mantained through the comprehension, so we start with a
company.branches, and must end with a
The inner type instead changes and is determined by the
yield expression: which is
valueList should be a