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尾部递归优化需要三件事:

  • 函数必须是自递归的
  • 函数每次调用只能调用自身一次
  • 自动呼叫必须处于尾部位置
  • 为了满足1。您需要将
    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
      }
    }