表达式的第一个是基本示例。第二个for-expr引入了一个轻微的变化,我认为会产生相同的输出。但由于编译错误而失败。是什么原因以及如何解决?
for {
n <- List(1,2)
c <- "ABC"
} yield s"$c$n"
//res0: List[String] = List(A1, B1, C1, A2, B2, C2)
for {
opt <- List(None, Some(1), None, None, Some(2), None)
n <- opt
c <- "ABC"
} yield s"$c$n"
//Error:(14, 5) type mismatch;
//found : scala.collection.immutable.IndexedSeq[String]
//required: Option[?]
// c <- "ABC"
// ^
答案 0 :(得分:2)
“修复”它的另一种方法是更改顺序:
for {
opt <- List(None, Some(1), None, None, Some(2), None)
c <- "ABC"
n <- opt
} yield s"$c$n"
//> List[String] = List(A1, B1, C1, A2, B2, C2)
这很有效,因为Scala可以将Option
转换为List
,但不能转向相反的方向。
事实上,它比简单的转换要复杂得多,涉及CanBuildFrom
。通常monad根本不构成,但在Scala中,有些使用CanBuildFrom
。
答案 1 :(得分:1)
回复标题问题:是的,第一个生成器&#34;设置心情&#34;为了整个表达。请注意,上面提到的for-expression是 desugared 到flatMap
的调用和最后的map
(加上withFilter
的守卫)。
在你的情况下,第一个for-expression是 desugared 到下面的表达式中:
List(1, 2).flatMap(n => "ABC".map(c => s"$c$n"))
这可以起作用,因为Predef
(在每个Scala程序中隐式导入)提供了String
到Seq[Char]
的隐式转换。
val implicitlyConverted: Seq[Char] = "ABC"
因此,它按类型检查运行。
现在让我们来看看第二个for-expression是如何 desugared :
List(None, Some(1), None, None, Some(2), None).flatMap(opt => opt.flatMap(n => "ABC".map(c => s"$c$n")))
同样,我们有与上面相同的类型错误,如果我们将表达式分成几行,我们可能会看到问题更好一点:
List(None, Some(1), None, None, Some(2), None).flatMap {
opt =>
opt.flatMap {
n =>
"ABC".map {
c =>
s"$c$n"
}
}
}
这给我们带来以下错误:
<console>:12: error: type mismatch;
found : scala.collection.immutable.IndexedSeq[String]
required: Option[?]
"ABC".map {
^
第二个flatMap
预计会产生Option[_]
,而map
内的"ABC".map(...)
会返回IndexedSeq[String]
。
所以,这就是原因。我们如何解决这个问题?最简单的解决方案可能涉及使用警卫并强制提取Option
中的值,如下所示:
for {
n <- List(None, Some(1), None, None, Some(2), None)
c <- "ABC" if n.isDefined
} yield s"$c${n.get}"
解决这一特定问题的一般方法涉及monad变换器,因为问题的根源在于monad不构成;问题非常广泛和复杂,或许this reply可能会给你一个更一般的答案。