为什么 For Comprehension 生成器会抑制 Option 类型?
Why does For Comprehension generator suppress Option type?
在下面的代码中,版本 1 给出了正确的结果。我对 V2 做了一个小改动。 None 值消失了,这没关系,因为 For Expression 就是这样工作的。但是,V2 中的 yield 输出不再遵循 myList.lift() 返回的数据类型(如 V1 中那样)的原因是什么?
val myList = List(12, 34, "ABC")
版本 1
for { i <- (0 to 3).toList } yield myList.lift(i)
// res1: List[Option[Any]] = List(Some(12), Some(34), Some(ABC), None)
版本 2
for {
i <- (0 to 3).toList
x <- myList.lift(i)
} yield x
// res2: List[Any] = List(12, 34, ABC)
如果你对 for comprehensions 去糖化
版本 1
List(0, 1, 2, 3).map({ i =>
myList.lift(i)
})
版本 2
List(0, 1, 2, 3).flatMap({ i =>
myList.lift(i).map({ x => x })
})
what is the reason the yield output in V2 no longer respects the data type returned by myList.lift()
yield
对 List.lift
的输出没有任何影响:
myList.lift(i)
returns Option[Any]
myList.lift(i).map({ x => x })
returns Option[Any]
是 flatMap
将 Option[Any]
扁平化为 Any
(通过丢弃 None
和展开 Some(a: Any) => a
)
第一种情况脱糖:
// desugar for comprehension:
(0 to 3).toList.map(
i => myList.lift(i))
第二种情况脱糖:
// desugar for comprehension:
(0 to 3).toList.flatMap(
i => myList.lift(i).map(
x => x))
// remove .map(x => x):
(0 to 3).toList.flatMap(
i => myList.lift(i))
// desugar flatMap:
(0 to 3).toList.map(
i => myList.lift(i)).flatten
第二种情况简化为第一种情况,末尾有一个.flatten
,这解释了结果的差异:res2 = res1.flatten
.
到底发生了什么?
Scala 可以将 Option
视为一个序列:
Some(foo) --> Seq(foo)
None --> Seq()
.flatten
只是将序列的序列展平。
如果您对类型感到好奇:
scala.collection.Seq.flatten
要求 'inner' 类型隐式转换为 GenTraversableOnce[T]
- 存在从
Option[T]
到 Iterable[T]
的全局隐式转换
Iterable[T] <: GenTraversableOnce[T]
<- 是什么意思?
x <- myList.lift(i)
中的 <-
不会 "t just assign a variable to a value, it " 从“myList.lift(i)
中获取值。当您 "get a value out of" 一个 Option[T]
时,您Some(foo)
得到 foo
而 None
什么都没有。"Getting nothing" 意味着 yield
没有 "t run at all for a None
, so nothing shows up in the result for the " 迭代”当 i = 3
.
如果您对为 Seq
、Option
和 Scala 中的许多其他类型定义的这个 "get a value out of" 概念感到好奇,它是为任何 Monad 定义的。
在下面的代码中,版本 1 给出了正确的结果。我对 V2 做了一个小改动。 None 值消失了,这没关系,因为 For Expression 就是这样工作的。但是,V2 中的 yield 输出不再遵循 myList.lift() 返回的数据类型(如 V1 中那样)的原因是什么?
val myList = List(12, 34, "ABC")
版本 1
for { i <- (0 to 3).toList } yield myList.lift(i)
// res1: List[Option[Any]] = List(Some(12), Some(34), Some(ABC), None)
版本 2
for {
i <- (0 to 3).toList
x <- myList.lift(i)
} yield x
// res2: List[Any] = List(12, 34, ABC)
如果你对 for comprehensions 去糖化
版本 1
List(0, 1, 2, 3).map({ i =>
myList.lift(i)
})
版本 2
List(0, 1, 2, 3).flatMap({ i =>
myList.lift(i).map({ x => x })
})
what is the reason the yield output in V2 no longer respects the data type returned by myList.lift()
yield
对 List.lift
的输出没有任何影响:
myList.lift(i)
returnsOption[Any]
myList.lift(i).map({ x => x })
returnsOption[Any]
是 flatMap
将 Option[Any]
扁平化为 Any
(通过丢弃 None
和展开 Some(a: Any) => a
)
第一种情况脱糖:
// desugar for comprehension:
(0 to 3).toList.map(
i => myList.lift(i))
第二种情况脱糖:
// desugar for comprehension:
(0 to 3).toList.flatMap(
i => myList.lift(i).map(
x => x))
// remove .map(x => x):
(0 to 3).toList.flatMap(
i => myList.lift(i))
// desugar flatMap:
(0 to 3).toList.map(
i => myList.lift(i)).flatten
第二种情况简化为第一种情况,末尾有一个.flatten
,这解释了结果的差异:res2 = res1.flatten
.
到底发生了什么?
Scala 可以将 Option
视为一个序列:
Some(foo) --> Seq(foo)
None --> Seq()
.flatten
只是将序列的序列展平。
如果您对类型感到好奇:
scala.collection.Seq.flatten
要求 'inner' 类型隐式转换为GenTraversableOnce[T]
- 存在从
Option[T]
到Iterable[T]
的全局隐式转换
Iterable[T] <: GenTraversableOnce[T]
<- 是什么意思?
x <- myList.lift(i)
中的 <-
不会 "t just assign a variable to a value, it " 从“myList.lift(i)
中获取值。当您 "get a value out of" 一个 Option[T]
时,您Some(foo)
得到 foo
而 None
什么都没有。"Getting nothing" 意味着 yield
没有 "t run at all for a None
, so nothing shows up in the result for the " 迭代”当 i = 3
.
如果您对为 Seq
、Option
和 Scala 中的许多其他类型定义的这个 "get a value out of" 概念感到好奇,它是为任何 Monad 定义的。