理解中的选项行为是Scala

时间:2018-02-24 11:23:27

标签: scala for-comprehension scala-option

两个新手问题。

似乎for理解了解Options并且可以自动跳过None并解开Some,例如

val x = Map("a" -> List(1,2,3), "b" -> List(4,5,6), "c" -> List(7,8,9))
val r = for {map_key <- List("WRONG_KEY", "a", "b", "c")
             map_value <- x get map_key } yield map_value

输出:

r: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))

Options去哪儿了?有人可以说明这是如何工作的?我们可以一直依赖这种行为吗?

第二件事是为什么这不编译?

val x = Map("a" -> List(1,2,3), "b" -> List(4,5,6), "c" -> List(7,8,9))
val r = for {map_key <- List("WRONG_KEY", "a", "b", "c")
                 map_value <- x get map_key
                 list_value <- map_value
    } yield list_value

它给出了

Error:(57, 26) type mismatch;
 found   : List[Int]
 required: Option[?]
             list_value <- map_value
                        ^

查看第一个示例的类型,我不确定为什么我们需要Option

4 个答案:

答案 0 :(得分:1)

因为理解被转换为对map或flatMap调用序列的调用。见here

您的for循环等同于

List("WRONG_KEY", "a", "b", "c").flatMap(
  map_key => x.get(map_key).flatMap(map_value => map_value)
)
flatMap中的

Option定义为

 @inline final def flatMap[B](f: A => Option[B]): Option[B]

因此,不允许传递List作为参数,因为编译器会通知您。

答案 1 :(得分:1)

我认为差异是由于在Seq特征中将理解扩展为map()和flatMap方法调用的方式。

为简明起见,我们定义一些变量:

var keys = List("WRONG_KEY", a, b, c)

您的第一个案例相当于:

val r = keys.flatMap(x.get(_))

而你的第二个案例相当于:

val r= keys.flatMap(x.get(_).flatMap{ case y => y })

我认为问题是Option.flatMap()应该返回一个Option [],这在第一种情况下很好,但在第二种情况下与x.get()。flatMap的传递不一致,这是一个List [Int]。

这些理解翻译规则在Wampler&amp; Sons的“Programming Scala”的第7章中有更详细的解释。佩恩。

答案 2 :(得分:1)

也许这个小差异,设置括号和调用flatten,说清楚:

scala> List("WRONG_KEY", "a", "b", "c").map (x get _)
res81: List[Option[List[Int]]] = List(None, Some(List(1, 2, 3)), Some(List(4, 5, 6)), Some(List(7, 8, 9)))

scala> List("WRONG_KEY", "a", "b", "c").map (x get _).flatten
res82: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))

这相当于:

path

中间值(map_key)在第二个块中消失为_。

答案 3 :(得分:1)

您正在for语句中混合两个不同的monad(ListOption)。这有时按预期工作,但并非总是如此。无论如何,您可以自己将选项转换为列表:

for {
  map_key <- List("WRONG_KEY", "a", "b", "c")
  list_value <- x get map_key getOrElse Nil 
} yield list_value