我有一个似乎无法使尾递归的函数。
我尝试使用额外的累加器创建辅助函数,但是该算法无法产生预期的结果,或者它实际上不是尾递归的。
这是功能:
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
}
}
提前感谢您的建议!
答案 0 :(得分:2)
嗯,n <- 1e7
呼叫ak <- function() {
m2 <- cbind(rep(seq_along(test), lengths(test)),
unlist(test))
testresult[m2] <- 1
}
wfw <- function() {
for (i in 1:length(test)) {
testresult3[i, test[[i]]] <- 1
}
}
library(microbemchmark)
microbenchmark(ak(), wfw(), unit = 'relative', times = 20L)
#Unit: relative
# expr min lq mean median uq max neval cld
# ak() 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 20 a
# wfw() 1.946415 1.945528 1.927263 1.926645 1.910907 1.940207 20 b
,game()
呼叫getStates()
。这看起来像蹦床可以处理的事情。
这里尝试使用TailCalls from the Standard Library。
getStates()
警告:在虚拟所有缺少的部分(game()
,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
}
}
等)后,我就可以编译它了,所以我实际上并没有尝试过运行 。下次,请发布足够的代码以使其成为minimal, complete, verifiable example。
答案 1 :(得分:1)
scala尾递归优化需要三件事:
为了满足1.您需要将game
的实现折叠为getStates
。
要满足2.难度更大,因为该foldLeft
调用可能会导致多个递归调用。解决方案是将availableSquares
列表传递给递归函数,并在每次调用中处理一个元素。这是最棘手的事情。
要满足3.您将需要使最终结果成为调用的参数,并在没有更多工作要做时返回该结果。进行递归调用时,会将新数据添加到结果中,然后将其与其他参数一起传递给
。这只是解决方案的概述,但希望对您有所帮助。