我正试图做一些可能导致Kotlin中的StackOverflow的操作。
知道这一点,我记得Kotlin支持tailrec
函数,所以我试着这样做:
private tailrec fun Turn.debuffPhase(): List<Turn> {
val turns = listOf(this)
if (facts.debuff == 0 || knight.damage == 0) {
return turns
}
// Recursively find all possible thresholds of debuffing
return turns + debuff(debuffsForNextThreshold()).debuffPhase()
}
令我惊讶的是,IDEA并未将其识别为tailrec
,我试图将其解除为扩展功能并使其成为正常功能:
private tailrec fun debuffPhase(turn: Turn): List<Turn> {
val turns = listOf(turn)
if (turn.facts.debuff == 0 || turn.knight.damage == 0) {
return turns
}
// Recursively find all possible thresholds of debuffing
val newTurn = turn.debuff(turn.debuffsForNextThreshold())
return turns + debuffPhase(newTurn)
}
即便如此,它也不被接受。重要的是,最后一个函数调用是否属于同一个函数?我知道+
是List
plus
函数的符号,但是它应该有所作为吗?我在互联网上看到的用于尾部调用其他语言的所有示例都允许这些actions。
我也试图用Int
做到这一点,这似乎比添加到列表更常用,但结果相同:
private tailrec fun discoverBuffsNeeded(dragon: RPGChar): Int {
val buffedDragon = dragon.buff(buff)
if (dragon.turnsToKill(initKnight) < 1 + buffedDragon.turnsToKill(initKnight)) {
return 0
}
return 1 + discoverBuffsNeeded(buffedDragon)
}
所有这些实现是否都不允许尾调用?我想到了其他一些方法来解决这个问题(比如将列表作为参数传递给MutableList
),但是在可能的情况下我会尽量避免在函数内部发送集合,这似乎应该是有可能。
PS:关于问题计划,我实施了problem的解决方案。
答案 0 :(得分:4)
您的所有示例都不是尾递归的。
尾调用是子例程中的最后一个调用。递归调用是对子程序的调用。尾递归调用是对子程序的尾调用。
在所有示例中,尾部调用是+
,而不是子例程。所以,所有这些都是递归的(因为它们自称),并且所有这些都有尾调用(因为每个子例程总是有#34;最后一次调用&#34;),但它们都不是尾递归的(因为递归呼叫不是最后一次通话。
中缀符号有时会模糊尾部调用的内容,当您以前缀形式或方法调用编写每个操作时更容易看到:
return plus(turns, debuff(debuffsForNextThreshold()).debuffPhase())
// or
return turns.plus(debuff(debuffsForNextThreshold()).debuffPhase())
现在变得更容易看到对debuffPhase
的调用不在尾部位置,而是调用plus
(即+
)处于尾部位置。如果Kotlin有一般的尾调用,那么 对plus
的调用确实会被消除,但是AFAIK,Kotlin只有尾递归(比如Scala),所以它不会。
答案 1 :(得分:0)
在不给出谜题的答案的情况下,这是一个非尾递归函数。
fun fac(n: Int): Int =
if (n <= 1) 1 else n * fac(n - 1)
这不是尾递归,因为递归调用不在尾部位置,正如Jörg的答案所指出的那样。
可以使用CPS,
将其转换为尾递归函数tailrec fun fac2(n: Int, k: Int = 1): Int =
if (n <= 1) k else fac2(n - 1, n * k)
虽然更好的界面可能会隐藏私人帮助函数的延续。
fun fac3(n: Int): Int {
tailrec fun fac_continue(n: Int, k: Int): Int =
if (n <= 1) k else fac_continue(n - 1, n * k)
return fac_continue(n, 1)
}