尾巴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 plusfunction的标志,但它应该有所作为? 我在互联网上看到的所有例子都是为了调用另一种语言而进行的。

我也试图用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) }