Black monkey house: Scala for optimizing annotations (tail recursion optimization)

Scala class library some notes, you can control the compiler optimizations, introduced about to begin

1, tail recursion @tailrec

object Module_WeiDG {
  @tailrec 
  def story(): Unit = {
    println("从前有座山,山上有座庙,庙里有个老和尚,一天老和尚对小和尚讲故事")
    story()
  }
}

尖叫提示:进入下一个函数,不再需要上一个函数的环境了,得出结果以后直接返回。尾递归调用,可以被转化成循环,这样能节约栈空间

2, non-tail recursion

def story(): Unit = { 
  println("从前有座山,山上有座庙,庙里有个老和尚,一天老和尚对小和尚讲故事")
  story()
  println("小和尚听了,找了一块豆腐撞死了")
}

尖叫提示:下一个函数结束以后,此函数还有后续,所以必须保存本身的环境以供处理返回值。

3, tail recursion optimization case

It may be converted to the recursive call cycles, so that the stack can save space. In functional programming, which is very important, we often use a recursive method to traverse the collection

(1) Non-tail recursion

object Util {
    def sum(xs: Seq[Int]): BigInt = {
        if (xs.isEmpty) 0 else xs.head + sum(xs.tail)
    }
        ...
}

The above sum method can not be optimized, because the calculation process, the final step is an addition, not a recursive call. Adjusted codes

(2) tail recursion optimization

def sum2(xs: Seq[Int], partial: BigInt): BigInt = {
    if (xs.isEmpty) partial else sum2(xs.tail, xs.head + partial)
}

Scala compiler will automatically optimize the application sum2 "tail recursion." If you call sum (1 to 1000000) a stack overflow error will occur. But sum2 (1 to 1000000, 0) will get the right result.

Although the Scala compiler will try to use the tail recursion optimization, but sometimes some of the less obvious reasons why it can not do so, such as more complex logic, if you want an error when the compiler can not optimize, you should give your add comment @tailrec method, so that, if the compiler can not optimize the application, it will error

(3) trampoline

Trampoline, interested can learn more about understanding yourself

import scala.util.control.TailCalls._
def evenLength(xs: Seq[Int]): TailRec[Boolean] = {
  if(xs.isEmpty) done(true) else tailcall(oddLength(xs.tail))
}

def oddLength(xs: Seq[Int]): TailRec[Boolean] = {
  if(xs.isEmpty) done(false) else tailcall(evenLength(xs.tail))
}

// 获得TailRec对象获取最终结果,可以用result方法
evenLength(1 to 1000000).result

尖叫提示:对于消除递归,一个更加通用的机制叫做“蹦床”。蹦床的实现会将执行一个循环,不停的调用函数。每个函数都返回下一个将被调用的函数。尾递归在这里是一个特例,每个函数都返回它自己。

Scala有一个名为TailCalls的工具对象,帮助我们轻松实现蹦床。相互递归的函数返回类型为TailRec[A],其要么返回done(result),要么返回tailcall(fun)。其中,fun是下一个被调用的函数。这必须是一个不带额外参数且同样返回TailRec[A]的函数上面是一个简单的示例

Reproduced in: https: //www.jianshu.com/p/b1d09316ccd6

Guess you like

Origin blog.csdn.net/weixin_33933118/article/details/91182520