@tailrec 如何工作

2024-03-01

我已经使用并阅读了@tailrec注释具有尾递归方法。我浏览了许多解释它的链接。例如,它仅在自调用函数时有效,并且不应被覆盖等。

到处都提到compiler optimizes。但是编译器做了什么魔法/概念来使其成为尾递归。对于下面的简单函数,编译器会做什么:

@tailrec def fact(acc: Int, n: Int): Int = {
  if (n <= 1) acc
  else fact(n * acc, n - 1)
}
fact(1,10)

我的意思是它是否将其转换为一个循环,反复调用它然后返回最终值?是否有任何解释它的论文链接


除了我对您的问题的评论(在此处重新粘贴代码):

  var acc = 1 
  var n = 10
start: 
  if (n <= 1) return acc 
  else { 
    acc = n * acc
    n = n - 1
    goto start
  }

我尝试编译fact我刚刚碰巧拥有的最近构建的方法scalac -Xprint:all不知怎的,编译器发出了一个icode文件。所以这确实说明了它如何优化尾部调用:

  // methods
  def fact(acc: Int (INT), n: Int (INT)): Int {
  locals: value acc, value n, value _$this
  startBlock: 1
  blocks: [1,2,3,4,5]

  1: 
    2   JUMP 2

  2: // huynhjl's comment: IF condition is here
    3   LOAD_LOCAL(value n)
    3   CONSTANT(1)
    3   CJUMP (INT)LE ? 3 : 4

  3: // huynhjl's comment: first branch of IF, will return acc
    3   LOAD_LOCAL(value acc)
    3   JUMP 5

  5: 
    2   RETURN(INT)

  4: // huynhjl's comment: else branch of IF, update acc and n and jump back
    4   LOAD_LOCAL(value n)
    4   LOAD_LOCAL(value acc)
    4   CALL_PRIMITIVE(Arithmetic(MUL,INT))
    4   LOAD_LOCAL(value n)
    4   CONSTANT(1)
    4   CALL_PRIMITIVE(Arithmetic(SUB,INT))
    4   STORE_LOCAL(value n)
    4   STORE_LOCAL(value acc)
    4   JUMP 2

  }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

@tailrec 如何工作 的相关文章

随机推荐