Scala 如何将递归函数转换为尾部递归版本?
我有一个函数,我似乎不能使尾部递归 我尝试过用额外的累加器创建辅助函数,但要么算法不能产生预期的结果,要么它实际上不是尾部递归的 以下是功能:Scala 如何将递归函数转换为尾部递归版本?,scala,recursion,Scala,Recursion,我有一个函数,我似乎不能使尾部递归 我尝试过用额外的累加器创建辅助函数,但要么算法不能产生预期的结果,要么它实际上不是尾部递归的 以下是功能: def game(boardState: BoardState, pieces: List[ChessPiece], acc: Set[BoardState]): Set[BoardState] = pieces match { case Nil => acc + boardS
def game(boardState: BoardState,
pieces: List[ChessPiece],
acc: Set[BoardState]): Set[BoardState] = pieces match {
case Nil => acc + boardState // No more pieces, boardState solved
case x :: xs => getStates(boardState, x, xs, acc)
}
def getStates(boardState: BoardState,
piece: ChessPiece,
rest: List[ChessPiece],
acc: Set[BoardState]): Set[BoardState] = {
// Ask if there are available squares
if (boardState.availableSquares.nonEmpty) {
// Get the states from every available square
boardState.availableSquares.foldLeft(Set[BoardState]())((innerAcc, sqr) => {
// Get the next chess piece
val nextPiece = buildPiece(piece, sqr)
// Check if placing the piece would result in an existing piece being attacked
if (boardState.withPieces.forall(sqr => !nextPiece.isAttacking(sqr))) {
// Do the recursion with the new Board State
val newState = boardState.placePiece(nextPiece)
innerAcc ++ game(newState, rest, acc) //This is the part that is not tail recursive
} else innerAcc
})
} else {
// There are no available places, search ends here
acc
}
}
提前感谢您的建议 Scala尾部递归优化需要三件事:
game
的实现折叠成getStates
满意的2。由于foldLeft
调用可能会导致多个递归调用,因此比较困难。解决方法是将availableSquares
列表传递给递归函数,并在每次调用中处理一个元素。这是最棘手的事情
满足3。您需要将最终结果作为调用的参数,并在没有更多工作要做时返回该结果。执行递归调用时,将新数据添加到结果中,并将其与其他参数一起传递
这只是解决方案的概要,但我希望它能有所帮助。Hmm,game()
调用getStates()
和getStates()
调用game()
。这看起来像蹦床可以处理的东西
这里有一个尝试使用
警告:我在对所有缺失的部分(
BoardState
,ChessPiece
,等等)进行了dummy处理之后,才得到了这个文件,所以我实际上没有尝试运行它。下次请发布足够的代码以使其成为一个。您能分享您的代码吗,它是编译的?我的意思是你也能分享BoardState,等等。它必须是final
我有一个更新,但现在我不知道它是否是递归的:(@JörgWMittag如果是method,是的,它必须是final
,但我个人不使用递归方法,我总是将递归函数嵌入外部方法中。这正如预期的那样工作,并且需要对代码进行较少的修改。非常酷,非常感谢!
import scala.util.control.TailCalls._
def game(boardState: BoardState,
pieces: List[ChessPiece],
acc: Set[BoardState]): TailRec[Set[BoardState]] = pieces match {
case Nil => done(acc + boardState) // No more pieces, boardState solved
case x :: xs => tailcall(getStates(boardState, x, xs, acc))
}
def getStates(boardState: BoardState,
piece: ChessPiece,
rest: List[ChessPiece],
acc: Set[BoardState]): TailRec[Set[BoardState]] = done{
// Ask if there are available squares
if (boardState.availableSquares.nonEmpty) {
// Get the states from every available square
boardState.availableSquares.foldLeft(Set[BoardState]())((innerAcc, sqr) => {
// Get the next chess piece
val nextPiece = buildPiece(piece, sqr)
// Check if placing the piece would result in an existing piece being attacked
if (boardState.withPieces.forall(sqr => !nextPiece.isAttacking(sqr))) {
// Do the recursion with the new Board State
val newState = boardState.placePiece(nextPiece)
innerAcc ++ tailcall(game(newState, rest, acc)).result
} else innerAcc
})
} else {
// There are no available places, search ends here
acc
}
}