如何在Scala中停止回溯?

如何在Scala中停止回溯?,scala,functional-programming,backtracking,Scala,Functional Programming,Backtracking,假设我正在用回溯法解决一个问题(例如,N-Queen)。如果我想找到唯一的(第一个)解决方案,而不是所有的解决方案,该怎么办 我想我可以强制执行(例如,使用可变布尔标志)。我想知道我怎样才能在功能上做到这一点 假设您使用的是递归搜索函数,那么您的函数应该返回一个结果(即皇后的位置)或者指示找不到该分支的结果。Scala可能有一个选项/可能类型,您可以使用它。这个建议同样适用于任何函数式语言。这里有一个简单的例子,深度优先搜索在找到所需内容时停止。如Chris K的回答所述,它使用了选项 case

假设我正在用回溯法解决一个问题(例如,
N-Queen
)。如果我想找到唯一的(第一个)解决方案,而不是所有的解决方案,该怎么办


我想我可以强制执行(例如,使用可变布尔标志)。我想知道我怎样才能在功能上做到这一点

假设您使用的是递归搜索函数,那么您的函数应该返回一个结果(即皇后的位置)或者指示找不到该分支的结果。Scala可能有一个选项/可能类型,您可以使用它。这个建议同样适用于任何函数式语言。

这里有一个简单的例子,深度优先搜索在找到所需内容时停止。如Chris K的回答所述,它使用了
选项

case class Tree[A](v: A, subtrees: Tree[A]*) {
  def dfs(s: A): Option[A] = {
    println("visiting " + v)
    subtrees.foldLeft(if(v == s) Some(v) else None)((r, t) => 
      if(r.isDefined) 
        r 
      else 
        t.dfs(s)
    )
  }
  override def toString() = "Tree(%s%s%s)".format(v, if(subtrees.nonEmpty) ", " else "", subtrees.mkString(", "))
}
用法:

scala> val t = Tree(1, Tree(2, Tree(3), Tree(4)), Tree(5, Tree(6), Tree(7)))
t: Tree[Int] = Tree(1, Tree(2, Tree(3), Tree(4)), Tree(5, Tree(6), Tree(7)))
t
看起来像

     1
   /   \
  2     5
 / \   / \
3   4 6   7    
因此,我们可以搜索元素并跟踪它访问的节点:

scala> t.dfs(6)
visiting 1
visiting 2
visiting 3
visiting 4
visiting 5
visiting 6
res42: Option[Int] = Some(6)

请注意,在找到我们要查找的内容后,我们不会再访问任何节点。

虽然Scala的
选项在这里起作用,但正如其他两个答案所指出的那样,更惯用的函数方法是在Scala中使用“惰性列表”或a来表示解决方案集

我发现自己在编写这样的代码,例如:

trait Node[A] {
  def children: Stream[A with Node[A]]

  def dfs(f: A => Boolean): Stream[A] = this.children.flatMap {
    child => if (f(child)) Stream(child) else child.dfs(f)
  }
}
现在假设我有一个
Board
类,该类扩展了
Node[Board]
,并且有一个
子类
方法的实现,该方法返回所有有效的Board和一个额外的块。假设它还有一些其他有用的东西,比如
size
方法,一个
为空的伴生对象,等等

然后,我可以编写以下内容以获得解决方案的

val solutions = Board.empty.dfs(_.size == 8)
是惰性的,只计算它的头部,所以现在我们只搜索了足够远的树来找到第一个解决方案。我们可以使用
head
获得此解决方案:

scala> solutions.head
res1: Board = 
o . . . . . . .
. . . . o . . .
. . . . . . . o
. . . . . o . .
. . o . . . . .
. . . . . . o .
. o . . . . . .
. . . o . . . .
或者别的什么。但如果我想要,我也可以得到其他结果:

scala> solutions(10)
res2: Board = 
. o . . . . . .
. . . . . . o .
. . . . o . . .
. . . . . . . o
o . . . . . . .
. . . o . . . .
. . . . . o . .
. . o . . . . .
这将搜索足够多的树,以找到第十个解决方案,然后停止


Stream
方法比
选项
方法的最大优点是,如果需要,我可以获得额外的结果,而无需为第一个结果支付更多费用。

是的,Scala确实有一种类型。您使用子类型
Some(value)
表示值,或使用子类型
None
表示无值。告诉函数您需要多少解决方案。我说不出话来。非常好的解决方案。