Ответ 1
Сначала о понимании. На него много ответов было много раз, что это абстракция над несколькими монадическими операциями: map
, flatMap
, withFilter
. Когда вы используете <-
, scalac desugars это строки в монадические flatMap
:
r <- monad
в monad.flatMap(r => ... )
он выглядит как обязательное вычисление (что такое монада), вы привязываете результат вычисления к r
. И часть yield
снимается в вызов map
. Тип результата зависит от типа monad
.
Future
trait имеет функции flatMap
и map
, поэтому мы можем использовать их для понимания. В вашем примере можно выделить следующий код:
future1.flatMap(r1 => future2.flatMap(r2 => future3.map(r3 => r1 + r2 + r3) ) )
Parallelism в стороне
Само собой разумеется, что если выполнение future2
зависит от r1
, вы не можете избежать последовательного выполнения, но если будущие вычисления независимы, у вас есть два варианта. Вы можете обеспечить последовательное выполнение или разрешить параллельное выполнение. Вы не можете принудительно использовать последнее, поскольку контекст выполнения будет обрабатывать это.
val res = for {
r1 <- computationReturningFuture1(...)
r2 <- computationReturningFuture2(...)
r3 <- computationReturningFuture3(...)
} yield (r1+r2+r3)
всегда будет выполняться последовательно. Это может быть легко объяснено desugaring, после чего последующие вызовы computationReturningFutureX
вызываются только внутри flatMaps.
val future1 = computationReturningFuture1(...)
val future2 = computationReturningFuture2(...)
val future3 = computationReturningFuture3(...)
val res = for {
r1 <- future1
r2 <- future2
r3 <- future3
} yield (r1+r2+r3)
может работать параллельно, а для понимания агрегирует результаты.