我在 Scala 2.10 中遇到语法问题。
for(a <- List(Some(1,2)); b <- a) yield b
评估为List(1,2)
那么为什么不for(a <- Some(List(1,2)); b <- a) yield b
评估同样的事情呢?
类型检查器抱怨第二个表达式 ( b <-a
) 说它List[Int]
在期待一个Option[?]
我在 Scala 2.10 中遇到语法问题。
for(a <- List(Some(1,2)); b <- a) yield b
评估为List(1,2)
那么为什么不for(a <- Some(List(1,2)); b <- a) yield b
评估同样的事情呢?
类型检查器抱怨第二个表达式 ( b <-a
) 说它List[Int]
在期待一个Option[?]
我最近对此进行了解释——希望有人能找到链接。这是一个反复出现的问题,因此很可能已关闭。
无论如何,外部生成器控制表示。这发生在每个级别,所以如果我有这个:
for {
a <- A
b <- B
c <- C
} yield f(a, b, c)
那么 的表示由f(a, b, c)
控制C
,that 的表示由 控制B
,最终结果的表示由 控制A
。因此,对于大多数实际目的,for comprehension 的表示由第一个生成器控制。
那么我所说的“代表”是什么意思?嗯,一个 for 理解通常是一个单子理解(实际上,它只是对像flatMap
and这样的方法的一组调用map
,所以它可以是任何类型检查的东西)。这意味着给定一个 monadM[A]
和一个 function A => M[B]
,然后您可以转换M[A]
,M[B]
其中M
monad 是“表示”。
这意味着,在大多数情况下,不可能在 for 理解中组合Option
和。List
所有集合在 中都有一个共同的父级GenTraversableOnce
,因此将它们组合起来没有问题(尽管事情比引擎盖下的要复杂得多)。
但是,存在从Option
to的隐式转换Iterable
。在这种情况下,当 Scalab <- a
在第一个示例中找到,并且知道它不能通过 anOption
因为理解被 a “控制”时List
,它会将 theOption
转换为 an Iterable
,并且一切正常。
但是,在第二种情况下不会发生这种情况。用 an 进行 for 理解是可以的Option
,因此无需将其转换为Iterable
. 不幸的是,无法将 a 转换List
为 an Option
(这种转换的结果是什么?),这会导致错误。
Scala 不会“回溯”a <- Some(List(1, 2))
并对其应用隐式转换,因为 Scala 中的类型推断只会继续进行——它之前决定的内容将保持原样。
我衷心建议您查看相关问题并了解 for comprehension 是如何翻译的。
丹尼尔解释了其中的复杂性。但我想补充一些细节,因为我发现这种行为非常不直观,而且我自己也遇到过这种混音Option
问题List
。这特别烦人,因为如您所见,它在一个方向上起作用,但在另一个方向上不起作用。
因此,根据您将拥有的理解规则
def test(a: Option[List[Int]]) = a.flatMap(_.map(identity))
失败
<console>:7: error: type mismatch;
found : List[Int]
required: Option[?]
def test(a: Option[List[Int]]) = a.flatMap(_.map(identity))
^
但是你可以让它工作:
def test(a: Option[List[Int]]) = (a: Iterable[List[Int]]).flatMap(_.map(identity))
test(Some(List(1,2))) // List(1,2)
或返回for
:
for(a <- Some(List(1,2)).toIterable; b <- a) yield b
应该for
自己强加这种转换吗?老实说,我不知道,但我和你一样感到惊讶,它不起作用。