Scala的理解效率如何?

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鼓励人们使用这种"语法糖",你总能看到大量使用过滤器,地图和平面图的代码,似乎程序员忘记了他们真正做的是将一个循环嵌套在另一个循环中,而实现的只是使代码看起来更短.你有什么想法?

Dan*_*ral 7

因为理解是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)

  • @ZZCat它没有"模拟"任何东西.它将语言翻译成其他东西,就像其他编译语言一样.否则,我们可以说每个面向对象的语言都"模拟"OO,因为它将其转换为机器代码. (2认同)

whe*_*ies 6

我编写代码使其易于理解和维护.然后我介绍一下 如果存在瓶颈,那就是我投入的注意力.如果它像你所描述的那样,我将以不同的方式攻击问题.在那之前,我喜欢"糖".这样可以省去写东西或思考问题的麻烦.