Scala 理解中的选项生成器强制其他生成器为选项?

Scala 理解中的选项生成器强制其他生成器为选项?,scala,for-comprehension,Scala,For Comprehension,表达式的第一个示例是基本示例。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), Non

表达式的第一个示例是基本示例。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"
//     ^
用于{

n回答标题问题:是的,第一个生成器为整个表达式“设置情绪”。请注意,对于像上面这样的表达式,会被分解为对
flatMap
s的调用和最后一个
map
(加上
带过滤器的
,用于警卫)

在您的情况下,第一个for表达式被分解为以下表达式:

List(1, 2).flatMap(n => "ABC".map(c => s"$c$n"))
这是因为
Predef
(在每个Scala程序中隐式导入)提供了
字符串
Seq[Char]
的隐式转换

val implicitlyConverted: Seq[Char] = "ABC"
因此,它会按计划检查运行类型

现在让我们看一下表达式的第二个for是如何被去除的:

同样,我们有与上面相同的类型错误,如果我们将表达式分成几行,我们可能会更好地看到这个问题:

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
s的调用和最终的
map
(加上用于保护的
withFilter

在您的情况下,第一个for表达式被分解为以下表达式:

List(1, 2).flatMap(n => "ABC".map(c => s"$c$n"))
这是因为
Predef
(在每个Scala程序中隐式导入)提供了
字符串
Seq[Char]
的隐式转换

val implicitlyConverted: Seq[Char] = "ABC"
因此,它会按计划检查运行类型

现在让我们看一下表达式的第二个for是如何被去除的:

同样,我们有与上面相同的类型错误,如果我们将表达式分成几行,我们可能会更好地看到这个问题:

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 {
                                ^
解决这一特定问题的更一般的方法涉及单子变压器,因为问题的根源是单子不构成;问题非常广泛和复杂,可能会给您一个更一般的答案。

另一种“修复”方法是更改顺序:

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)
用于{
opt另一种“修复”方法是更改顺序:

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)
用于{

在本例中选择“是”,因为第二个提取器类似于一个
flatMap
,因此您需要返回一个选项。为清楚起见,在第一种情况下,由于隐式转换,您可以在“ABC”上提取,因此该内容将成为一个列表并进行编译,在第二种情况下为“ABC”未隐式转换为选项。在本例中为“是”,因为第二个提取器类似于
flatMap
,因此您需要返回一个选项。为清楚起见,在第一种情况下,由于隐式转换,您可以在“ABC”上提取,因此该内容将成为列表并进行编译,在第二种情况下为“ABC”未隐式转换为选项。答案的学术质量超出预期。非常感谢。@谢谢,我很高兴我提供了帮助!答案的学术质量超出预期。非常感谢。@谢谢,我很高兴我提供了帮助!