我已经使用并阅读了关于@tailrec
注释的尾部递归方法。我已经通过许多链接解释了它。例如,它仅适用于自调用函数,不应覆盖等。
在任何地方都提到了compiler optimizes
。但是编译器做了什么魔术/概念来使其尾递归。对于下面的简单函数,编译器会做什么:
@tailrec def fact(acc: Int, n: Int): Int = {
if (n <= 1) acc
else fact(n * acc, n - 1)
}
fact(1,10)
我的意思是它将它转换为循环,重复调用它然后返回最终值?是否有任何链接到纸张解释它
答案 0 :(得分:11)
除了我对你的问题的评论(在这里重新编写代码):
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
}
答案 1 :(得分:8)