在 Scala 中避免 while 循环有什么好处吗? [英] Is there any advantage to avoiding while loops in Scala?

查看:65
本文介绍了在 Scala 中避免 while 循环有什么好处吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

阅读专家编写的 Scala 文档可以得到尾递归比 while 循环更好的印象,即使后者更简洁明了.这是一个例子

Reading Scala docs written by the experts one can get the impression that tail recursion is better than a while loop, even when the latter is more concise and clearer. This is one example

object Helpers {
    implicit class IntWithTimes(val pip:Int) {
            // Recursive
        def times(f: => Unit):Unit = {
            @tailrec
            def loop(counter:Int):Unit = {
                if (counter >0) { f; loop(counter-1) }
            }
            loop(pip)
        }

            // Explicit loop
        def :@(f: => Unit) = {
            var lc = pip
            while (lc > 0) { f; lc -= 1 }
        }   
    }
}   

(需要明确的是,专家根本没有解决循环问题,但在示例中,他们本能地选择以这种方式编写循环,这就是向我提出的问题:我应该开发一个类似的本能..)

(To be clear, the expert was not addressing looping at all, but in the example they chose to write a loop in this fashion as if by instinct, which is what the raised the question for me: should I develop a similar instinct..)

while 循环唯一可能更好的方面是迭代变量应该是循环体的局部变量,并且变量的变异应该在一个固定的位置,但是 Scala 选择不提供这种语法.

The only aspect of the while loop that could be better is the iteration variable should be local to the body of the loop, and the mutation of the variable should be in a fixed place, but Scala chooses not to provide that syntax.

清晰度是主观的,但问题是(尾)递归样式是否提供了改进的性能?

Clarity is subjective, but the question is does the (tail) recursive style offer improved performance?

推荐答案

我很确定,由于 JVM 的限制,并不是每个潜在的尾递归函数都会被 Scala 编译器优化掉,所以对您关于性能的问题的简短(有时是错误的)答案是否定的.

I'm pretty sure that, due to the limitations of the JVM, not every potentially tail-recursive function will be optimised away by the Scala compiler as so, so the short (and sometimes wrong) answer to your question on performance is no.

对您更笼统的问题(具有优势)的长回答有点做作.请注意,通过使用 while,您实际上是:

The long answer to your more general question (having an advantage) is a little more contrived. Note that, by using while, you are in fact:

  1. 创建一个保存计数器的新变量.
  2. 改变那个变量.

逐一错误和可变性的危险将确保从长远来看,您将使用 while 模式引入错误.事实上,你的 times 函数可以很容易地实现为:

Off-by-one errors and the perils of mutability will ensure that, on the long run, you'll introduce bugs with a while pattern. In fact, your times function could easily be implemented as:

def times(f: => Unit) = (1 to pip) foreach f

这不仅更简单更小,而且避免了任何瞬态变量和可变性的创建.事实上,如果你调用的函数的类型对结果很重要,那么 while 结构将开始变得更加难以阅读.请尝试仅使用 whiles 来实现以下内容:

Which not only is simpler and smaller, but also avoids any creation of transient variables and mutability. In fact, if the type of the function you are calling would be something to which the results matter, then the while construction would start to be even more difficult to read. Please attempt to implement the following using nothing but whiles:

def replicate(l: List[Int])(times: Int) = l.flatMap(x => List.fill(times)(x))

然后继续定义一个执行相同操作的尾递归函数.

Then proceed to define a tail-recursive function that does the same.

更新:

我听到你说:嘿!那是作弊!foreach 既不是 while 也不是 tail-rec 调用".哦真的吗?看看 Scala 对 Listsforeach 定义:

I hear you saying: "hey! that's cheating! foreach is neither a while nor a tail-rec call". Oh really? Take a look into Scala's definition of foreach for Lists:

  def foreach[B](f: A => B) {
    var these = this
    while (!these.isEmpty) {
      f(these.head)
      these = these.tail
    }
  }

如果您想了解有关 Scala 递归的更多信息,请查看 这篇博文.一旦你进入函数式编程,疯狂阅读 Rúnar 的 博文.更多信息这里此处.

If you want to learn more about recursion in Scala, take a look at this blog post. Once you are into functional programming, go crazy and read Rúnar's blog post. Even more info here and here.

这篇关于在 Scala 中避免 while 循环有什么好处吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆