Saw*_*yer 3 scala for-comprehension
在第23章"Scala编程"一书中,作者给出了一个例子:
case class Book(title: String, authors: String*)
val books: List[Book] = // list of books, omitted here
// ?nd all authors who have published at least two books
for (b1 <- books; b2 <- books if b1 != b2;
a1 <- b1.authors; a2 <- b2.authors if a1 == a2)
yield a1
Run Code Online (Sandbox Code Playgroud)
作者说,这将转化为:
books flatMap (b1 =>
books filter (b2 => b1 != b2) flatMap (b2 =>
b1.authors flatMap (a1 =>
b2.authors filter (a2 => a1 == a2) map (a2 =>
a1))))
Run Code Online (Sandbox Code Playgroud)
但是如果你查看map和flatmap方法定义(TraversableLike.scala),你可能会发现,它们被定义为for循环:
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
b.sizeHint(this)
for (x <- this) b += f(x)
b.result
}
def flatMap[B, That](f: A => Traversable[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
for (x <- this) b ++= f(x)
b.result
}
Run Code Online (Sandbox Code Playgroud)
好吧,我想这将继续被翻译为foreach,然后翻译成while语句,这是一个构造而不是表达式,scala没有for构造,因为它希望for总是产生一些东西.
所以,我想和你讨论的是,为什么Scala这样做"翻译"?作者的例子使用了4个生成器,最后将被转换为4级嵌套for循环,我认为当books它很大时它会有非常可怕的性能.
Scala鼓励人们使用这种"语法糖",你总能看到大量使用过滤器,地图和平面图的代码,似乎程序员忘记了他们真正做的是将一个循环嵌套在另一个循环中,而实现的只是使代码看起来更短.你有什么想法?
因为理解是monadic变换的语法糖,因此,在各种各样的地方都很有用.在那里,它们在Scala中比在等效的Haskell构造中更冗长(当然,Haskell默认情况下是非严格的,因此不能像Scala那样谈论构造的性能).
同样重要的是,这种结构可以保持清晰的工作,避免快速升级的缩进或不必要的私有方法嵌套.
至于最后的考虑,无论是否隐藏复杂性,我都会认为:
for {
b1 <- books
b2 <- books
if b1 != b2
a1 <- b1.authors
a2 <- b2.authors
if a1 == a2
} yield a1
Run Code Online (Sandbox Code Playgroud)
很容易看出正在做什么,复杂性很明显:b ^ 2*a ^ 2(过滤器不会改变复杂性),书籍数量和作者数量.现在,使用深度缩进或私有方法在Java中编写相同的代码,并尝试快速确定代码的复杂性.
因此,imho,这并不掩盖复杂性,相反,它表明了这一点.
至于你提到的map/ flatMap/ filter定义,它们不属于List任何其他类,因此它们不会被应用.基本上,
for(x <- List(1, 2, 3)) yield x * 2
Run Code Online (Sandbox Code Playgroud)
被翻译成
List(1, 2, 3) map (x => x * 2)
Run Code Online (Sandbox Code Playgroud)
这不是一回事
map(List(1, 2, 3), ((x: Int) => x * 2)))
Run Code Online (Sandbox Code Playgroud)
这就是你传递的定义将被调用的方式.为了记录,mapon 的实际实现List是:
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
b.sizeHint(this)
for (x <- this) b += f(x)
b.result
}
Run Code Online (Sandbox Code Playgroud)
我编写代码使其易于理解和维护.然后我介绍一下 如果存在瓶颈,那就是我投入的注意力.如果它像你所描述的那样,我将以不同的方式攻击问题.在那之前,我喜欢"糖".这样可以省去写东西或思考问题的麻烦.