Scala表示尾部递归形式的表达式

时间:2017-03-19 10:11:27

标签: scala tail-recursion for-comprehension

我试图想出一种有效的方法将for-expression N皇后解决方案转换为尾递归形式,并且仍然保留使用for语法实现的惯用性,这有点问题。任何想法都非常受欢迎。

def place(boardSize: Int, n: Int): Solutions = n match {
  case 0 => List(Nil)
  case _ =>
    for {
      queens <- place(boardSize, n - 1)
      y <- 1 to boardSize
      queen = (n, y)
      if (isSafe(queen, queens))
    } yield queen :: queens
}

def isSafe(queen: Queen, others: List[Queen]) = {...}

1 个答案:

答案 0 :(得分:1)

您所写的内容基本上与所谓的深度优先搜索(DFS)相对应。

虽然很容易编写DFS的递归实现,但它不是尾递归的。这是一个尾递归的提议。请注意,我测试此代码,但它至少应该让您知道如何继续。

def solve(): List[List[Int]] = {
  @tailrec def solver(fringe: List[List[Int]], solutions: List[List[Int]]): List[List[Int]] = fringe match {
    case Nil => solutions
    case potentialSol :: fringeTail =>
      if(potentialSol.length == n) // We found a solution
        solver(fringe.tail, potentialSol.reverse :: solutions)
      else { // Keep looking
        val unused = (1 to n).toList filterNot potentialSol.contains
        val children = for(u <- unused ; partial = u :: fringe.head if isValid(partial)) yield partial
        solver(children ++ fringe.tail, solutions)
      }
  }
  solver((1 to n).toList.map(List(_)), Nil).map(_.reverse)
}

如果您关注性能,请注意此解决方案非常差,因为它对不可变数据结构使用了较慢的操作,并且因为在JVM上您最好使用性能重要的迭代。当n增加时,这将开始非常快速地失败。从算法上讲,解决NQueens的方法比使用DFS要好得多。