为什么 for-comprehension 扩展为 map+foreach 而不是嵌套的 foreach?
Why for-comprehension expands to map+foreach instead of nested foreach?
我想我认为的理解是 "for every 'a' create 'x' and then for every 'b' do some stuff with all of vars"
for {
a <- Seq(1, 2, 3)
x = "test" + a
b <- Seq(4, 5, 6)
} {
...
}
应该扩展到
Seq(1, 2, 3).foreach { a =>
val x = "test" + a
Seq(4, 5, 6).foreach { b =>
...
}
}
但令人惊讶地检查 -Xprint:parser
显示它扩展到
Seq(1, 2, 3).map { a =>
val x = "test" + a
(a, x)
}.foreach { case (a, x) =>
Seq(4, 5, 6).foreach { b =>
...
}
}
我认为它打破了对整个 for-comprehension 中发生的事情的自然理解,因为现在它首先定义三个不同的 'x' 然后执行其他东西。如果 'x' 的定义会产生副作用,那么对 map
进行脱糖的目的是什么?
这种行为令人惊讶,但它记录在 Scala 规范中:https://scala-lang.org/files/archive/spec/2.13/06-expressions.html#for-comprehensions-and-for-loops
根据最后一条规则:
A generator <- followed by a value definition ′ = ′ is translated to the following generator of pairs of values, where and ′ are fresh names:
(, ′) <- for (@ <- ) yield { val ′@′ = ′; (, ′) }
所以当有一个值定义时,Scala 总是插入一个新的带有 yield
的 for-comprehension,然后变成 map
.
并且如果将值定义行 x = "test" + a
替换为生成器 x <- Seq("test" + a)
,结果将变为预期的结果:
Seq(1, 2, 3)
.foreach(((a) => Seq("test".$plus(a))
.foreach(((x) => Seq(4, 5, 6)
.foreach(((b) => ...))))))
我想我认为的理解是 "for every 'a' create 'x' and then for every 'b' do some stuff with all of vars"
for {
a <- Seq(1, 2, 3)
x = "test" + a
b <- Seq(4, 5, 6)
} {
...
}
应该扩展到
Seq(1, 2, 3).foreach { a =>
val x = "test" + a
Seq(4, 5, 6).foreach { b =>
...
}
}
但令人惊讶地检查 -Xprint:parser
显示它扩展到
Seq(1, 2, 3).map { a =>
val x = "test" + a
(a, x)
}.foreach { case (a, x) =>
Seq(4, 5, 6).foreach { b =>
...
}
}
我认为它打破了对整个 for-comprehension 中发生的事情的自然理解,因为现在它首先定义三个不同的 'x' 然后执行其他东西。如果 'x' 的定义会产生副作用,那么对 map
进行脱糖的目的是什么?
这种行为令人惊讶,但它记录在 Scala 规范中:https://scala-lang.org/files/archive/spec/2.13/06-expressions.html#for-comprehensions-and-for-loops
根据最后一条规则:
A generator <- followed by a value definition ′ = ′ is translated to the following generator of pairs of values, where and ′ are fresh names:
(, ′) <- for (@ <- ) yield { val ′@′ = ′; (, ′) }
所以当有一个值定义时,Scala 总是插入一个新的带有 yield
的 for-comprehension,然后变成 map
.
并且如果将值定义行 x = "test" + a
替换为生成器 x <- Seq("test" + a)
,结果将变为预期的结果:
Seq(1, 2, 3)
.foreach(((a) => Seq("test".$plus(a))
.foreach(((x) => Seq(4, 5, 6)
.foreach(((b) => ...))))))