尾巴rec kotlin名单
我正在尝试做一些操作,只会在Kotlin中导致一个StackOverflow。
知道了,我记得Kotlin支持tailrec
函数,所以我试着做:
private tailrec fun Turn.debuffPhase(): List { 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
,我试图tailrec
它的扩展function,并使其正常的function:
private tailrec fun debuffPhase(turn: Turn): List { 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) }
即使如此也不被接受。 重要的是不是最后的函数调用是相同的function? 我知道+
是List
plus
function的标志,但它应该有所作为? 我在互联网上看到的所有例子都是为了调用另一种语言而进行的。
我也试图用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:关于问题程序,我正在实施一个解决这个问题的方法 。
你的例子都不是尾递归的。
尾部呼叫是子程序中的最后一个呼叫。 递归调用是对其自身的子例程的调用。 尾递归调用是自身子程序的尾调用。
在你所有的例子中,尾部调用是+
,而不是子程序。 因此,所有这些都是递归的(因为他们自己调用自己),所有这些都有尾调用(因为每个子例程总是有一个“最后一次调用”),但没有一个是尾递归的(因为递归调用不是最后的呼叫)。
中缀符号有时会遮蔽尾部调用的内容,当以前缀forms或方法调用编写每个操作时,会更容易看出:
return plus(turns, debuff(debuffsForNextThreshold()).debuffPhase()) // or return turns.plus(debuff(debuffsForNextThreshold()).debuffPhase())
现在,看到debuffPhase
的调用不是在尾部位置,而是在尾部位置的plus
(即+
)的调用变得更容易。 如果Kotlin有通用的尾部调用,那么plus
调用确实会被消除,但是AFAIK,Kotlin只有尾部递归(就像Scala),所以不会。
没有给你一个解答的答案,这是一个非尾递归函数。
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)
虽然更好的界面可能会隐藏私人帮手function的延续。
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) }