类型必须在 for 理解中对齐是什么意思?

Bla*_*man 1 scala for-comprehension

有人可以详细说明当类型必须与 Scala 保持一致以进行理解时这意味着什么吗?

for {
..
..
}
Run Code Online (Sandbox Code Playgroud)

如果调用都返回 Futures 那么它会好吗?只是想了解它什么时候起作用,什么时候不起作用。

Mar*_*lic 5

对 map/flatMap 调用的理解性脱糖,因此请考虑它们的签名。例如,考虑Option#flatMap

def flatMap[B](f: (A) => Option[B]): Option[B]
Run Code Online (Sandbox Code Playgroud)

我们看到Options 继续参与。现在观察自

for {
  a <- Some(41)
  b <- Some(1)
} yield a + b
Run Code Online (Sandbox Code Playgroud)

变成

Some(41).flatMap(a => Some(1).map(b => a + b))
Run Code Online (Sandbox Code Playgroud)

这意味着如果您尝试在 for-comprehension 中混合使用 monadic 类型,例如

for {
  a <- Some(41)
  b <- Try(1)
} yield a + b
Run Code Online (Sandbox Code Playgroud)

然后它会脱糖

Some(41).flatMap(a => Try(1).map(b => a + b))
                       |
                  types do not align
Run Code Online (Sandbox Code Playgroud)

但我们已经看到Option#flatMap期望A => Option[B]不是A => Try[B]

一个似乎可以打破该规则的地方是将 Option 与 List 混合使用时

scala> for {
     |   a <- List(41)
     |   b <- Some(1)
     | } yield (a + b)
val res0: List[Int] = List(42)
Run Code Online (Sandbox Code Playgroud)

但这是有效的,因为List#flatMapAto获取一个函数IterableOnce并且Option已经IterableOnce在 Scala 2.13 中制作

def flatMap[B](f: A => IterableOnce[B])
Run Code Online (Sandbox Code Playgroud)

请注意,相反的方式将不起作用:

scala> for {
     |   a <- Some(41)
     |   b <- List(1)
     | } yield a + b
         b <- List(1)
           ^
On line 3: error: type mismatch;
        found   : List[Int]
        required: Option[?]
Run Code Online (Sandbox Code Playgroud)

一般来说,给定一个有效的类型F[A]F除非我们使用子类型,否则内部 for-comprehension不能改变,另一方面A确实可以改变。