在Scala 2.10中,我遇到了for-comprehension的语法问题。
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[?]
发布于 2013-02-19 12:56:56
我最近已经解释过这一点--希望有人能找到其中的联系。这是一个反复出现的问题,所以它很可能会被关闭。
无论如何,外部生成器控制表示。这在每一层都会发生,所以如果我有这个:
for {
a <- A
b <- B
c <- C
} yield f(a, b, c)然后,f(a, b, c)的表示由C控制,B的表示由B控制,最终结果的表示由A控制。因此,对于大多数实际目的,for purposes的表示是由第一个生成器控制的。
那么,我所说的“代表性”是什么意思?for monadic通常是一元理解(实际上,它只是对flatMap和map等方法的一组调用,所以它可以是任何类型检查的内容)。这意味着给定一个单数M[A]和一个函数A => M[B],然后您可以在M[B]中转换M[A],其中单数M是“表示”。
这意味着,在大多数情况下,不可能将Option和List组合在一起以进行理解。所有的集合在GenTraversableOnce中都有一个共同的父类,所以组合它们没有问题(尽管事情比幕后复杂得多)。
但是,存在从Option到Iterable的隐式转换。在这种情况下,当Scala在第一个示例中找到b <- a,并且知道它不能传递Option,因为理解是由List“控制”的,它将Option转换为Iterable,然后一切正常。
然而,在第二种情况下不会发生这种情况。用Option做一个for理解是可以的,所以不需要把它转换成一个Iterable。不幸的是,无法将List转换为Option (这种转换的结果会是什么?),这会导致错误。
Scala不会“回溯”到a <- Some(List(1, 2))并对其应用隐式转换,因为Scala中的类型推断只会向前推进--它之前所做的决定将保持不变。
我强烈建议您查看相关的问题,并了解如何翻译for comprehension。
发布于 2013-02-19 16:59:01
丹尼尔解释了其中的复杂之处。但我想补充一些细节,因为和你一样,我发现这种行为非常不直观,我自己也遇到过几次将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 bfor是否应该自己强制执行此转换?老实说,我不知道,但我和你一样惊讶于它不起作用。
https://stackoverflow.com/questions/14949831
复制相似问题