2013-02-19 62 views
2

我在Scala 2.10中遇到了用于理解的语法问题。在Scala中用于理解的补救语法问题

for(a <- List(Some(1,2)); b <- a) yield b评估为List(1,2)

那么为什么不for(a <- Some(List(1,2)); b <- a) yield b评价同一件事?

的类型检查抱怨说,它发现了一个List[Int] 期待的Option[?]

+0

可能的重复[类型不匹配Scala理解](http://stackoverflow.com/questions/4719592/type-mismatch-on-scala-for-comprehension) – 2013-02-19 07:06:49

+0

它也是重复的[困惑与for-理解到flatMap/map转换](http://stackoverflow.com/questions/14598990/confused-with-the-for-comprehension-to-flatmap-map-transformation) – 2013-02-19 08:55:48

回答

7

当我说明了这是最近第二个表达式(b <-a) - 希望有人能找到的链接。这是一个反复出现的问题,所以它可能会被关闭。

无论如何,外部生成器控制着表示。这发生在每一个级别,所以如果我有这样的:

for { 
    a <- A 
    b <- B 
    c <- C 
} yield f(a, b, c) 

随后的f(a, b, c)表示由C控制,那表示由B控制,最终结果的表述由A控制。因此,对于大多数实际用途,理解的表示由第一个生成器控制。

那么“代表性”是什么意思?那么,理解是一个单子理解,通常(实际上,这只是一组调用方法,如flatMapmap,所以它可以是任何 typechecks)。这意味着给定一个单子M[A]和一个函数A => M[B],那么你可以在M[B]中变换M[A],其中单子的M是“表示”。

这意味着,在大多数情况下,将OptionList组合在一起用于理解是不可能的。所有的藏品在GenTraversableOnce中都有一个共同的父项,所以在组合它们时没有任何问题(尽管事情比底层的要复杂得多)。

但是,存在从OptionIterable的隐式转换。既然如此,当斯卡拉在第一个例子中发现b <- a,并且知道它不能通过Option,因为理解由List“控制”,它将Option转换为Iterable,并且一切正常。

但是,在第二种情况下不会发生这种情况。做一个Option的理解是好的,所以没有必要将它转换成Iterable。遗憾的是,不能将List转换为Option(这种转换的结果是什么?),这会导致错误。

Scala不会“回溯”到a <- Some(List(1, 2))并对其应用隐式转换,因为Scala中的类型推断只能继续前进 - 它之前决定的内容将保持不变。

我衷心推荐你看看相关的问题,并理解翻译理解的方式。

+0

谢谢丹尼尔。如果问题是重复的,我不会感到惊讶,因为它很难搜索,关于理解的“斯卡拉之旅”doc不能解释这种行为。真正绊倒我的是(a < - Some(List(1,2)); b <-a){println(b)}的行为与我预期的相同,即'b'评估为潜在的Ints。 – 2013-02-19 15:53:58

+0

@DanielSchobel那么,如果没有“收益率”,你没有返回任何东西,所以没有问题。既然你不能有'一些(1,2)',你不能有'yield'版本。 – 2013-02-19 23:22:49

2

丹尼尔解释了这个错综复杂。但是我想补充一些细节,因为就你而言,我发现这种行为令人难以置信地不直观,而且我遇到了几次混合OptionList的问题。这是特别烦人的,因为如你所见,它在一个方向而不是另一个方向工作。

所以根据换理解规则,你将有

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应该自己强加这个转换吗?我不太清楚,但我分享你的惊喜,它不起作用。

+0

Upvoted for the work-around,我同意,它似乎应该以原始形式工作,特别是在我对Daniel的评论中指出,对于(a < - Some(List(1,2)); b < - a){println(b)}的工作原理与您所期望的完全相同,即b对底层的Ints进行了处理。 – 2013-02-19 16:01:47