Clojure 调用10上的sol计数时出现堆栈溢出(N-queens程序)

Clojure 调用10上的sol计数时出现堆栈溢出(N-queens程序),clojure,stack-overflow,n-queens,Clojure,Stack Overflow,N Queens,这是我第一次用clojure编程,我的程序遇到了stackoverflow的一些问题。这个程序基本上是试图找到解决N皇后问题的所有可能的方法 当我在10或更高的值上调用sol count(查找给定N的解的数量)时,我得到一个堆栈溢出 (defn qextends? "Returns true if a queen at rank extends partial-sol." [partial-sol rank] (if (>= (count partial-sol) 1)

这是我第一次用clojure编程,我的程序遇到了stackoverflow的一些问题。这个程序基本上是试图找到解决N皇后问题的所有可能的方法

当我在10或更高的值上调用sol count(查找给定N的解的数量)时,我得到一个堆栈溢出

(defn qextends?
  "Returns true if a queen at rank extends partial-sol."
  [partial-sol rank]
  (if (>= (count partial-sol) 1)
    (and
      (not= (first partial-sol) (- rank (count partial-sol)))
      (not= (first partial-sol) (+ rank (count partial-sol)))
      (not= (first partial-sol) rank)
      (qextends? (rest partial-sol) rank))
    true)
  )

(defn qextend-helper [n x partial-sol partial-sol-list]
  (if (<= x n)
    (if (qextends? partial-sol x)
      (qextend-helper n (inc x) partial-sol (conj partial-sol-list (conj partial-sol x)))
      (qextend-helper n (inc x) partial-sol partial-sol-list)
    )
  partial-sol-list)
  )


(defn qextend
  "Given a vector *partial-sol-list* of all partial solutions of length k,
  returns a vector of all partial solutions of length k + 1.
  "
  [n partial-sol-list]
  (if (>= (count partial-sol-list) 1)
    (vec (concat (qextend-helper n 1 (first partial-sol-list) [])
      (qextend n (rest partial-sol-list))))
    nil))

(defn sol-count-helper
  [n x partial-sol-list]
  (if (<= x (- n 1))
    (sol-count-helper n (+ 1 x) (qextend n partial-sol-list))
    (qextend n partial-sol-list))
  )

(defn sol-count
  "Returns the total number of n-queens solutions on an n x n board."
  [n]
  (count (sol-count-helper n 1 [[]]))
  )
(定义qextends?
“如果级别为的皇后扩展了部分sol,则返回true。”
[部分信保级]
(如果(>=(计算部分溶胶)1)
(及
(非=(第一部分溶胶)(-rank(count部分溶胶)))
(非=(第一部分溶胶)(+秩(计数部分溶胶)))
(非=(第一部分sol)等级)
(qextends?(剩余部分sol)秩)
(对)
)
(defn qextend helper[n x部分sol部分sol列表]
(如果(=(计算部分sol列表)1)
(vec(concat(qextend helper n1(第一部分sol列表)[]))
(qextend n(剩余部分sol列表)))
(零)
(定义sol count helper)
[n x部分溶胶列表]

(如果(对于初学者来说,Clojure不像其他Lisp那样具有TCO。为了缓解这一问题,Clojure提供了。在Clojure和其他Lisp中,您通常没有显式的返回,相反,重点是返回值

我安装了qextend帮助程序,为您提供了一个开始。我针对我在此处替换的代码段测试了您的一些答案,它们都解析为相同的解决方案。即使在其中包含此代码段,您仍然无法超过10,但如果您继续删除所有尾部调用递归,您应该能够克服stackoverflow错误:

(defn qextend-helper [n x partial-sol partial-sol-list]
  (loop [n n
         x x
         partail-sol partial-sol
         partial-sol-list partial-sol-list]
    (when (and (<= x n)
               (qextends? partail-sol x))
      (recur n (inc x) partail-sol (conj partial-sol-list (conj partial-sol x))))))
最后,这种缩进样式和将括号放在自己的行上并不能提高可读性

      (qextend-helper n (inc x) partial-sol partial-sol-list)
    )
  partial-sol-list)
  )

完成dizzystar的回答:

大多数递归可以是
recur
red:您可以将
recur
放在
if
中,从而在
下,将宏扩展到
if
窗体。例如

(defn qextend-helper [n x partial-sol partial-sol-list]
  (if (<= x n)
    (if (qextends? partial-sol x)
      (recur n (inc x) partial-sol (conj partial-sol-list (conj partial-sol x)))
      (recur n (inc x) partial-sol partial-sol-list))
    partial-sol-list)
  )
…无法通过
recur
处理,因为它隐藏在对
concat
vec
的函数调用中

您可以通过返回a来解决此问题,从而使
partial sol list
参数变懒:

  • 摆脱vec
-返回序列-和
  • concat
    替换为
    lazy cat
  • 结果函数是

    (defn qextend [n partial-sol-list]
      (if (seq partial-sol-list)
        (lazy-cat (qextend-helper n 1 (first partial-sol-list) [])
                (qextend n (rest partial-sol-list)))
        nil))
    
    您还必须避免
    count
    ing(从而实现)延迟序列:因此使用
    seq
    来测试
    部分sol列表中是否有任何内容

    它起作用了

    => (sol-count 11)
    2680
    

    哇,这真的很好。但我现在遇到的一个问题是qextend需要返回一个向量,而使用lazy cat我最终得到了一系列的解决方案。是否有某种类型的lazy vec可以生成一个向量?为什么“qextend”必须返回一个向量向量向量?为什么向量序列不能?并没有lazy vector,但你们可以将解决方案序列转换为向量,例如“(vec(sol count helper 8 1[[]]))”。还有其他依赖qextends的函数需要将其转换为向量。该答案有效,但sol count返回的计数非常理想,我希望它是qextends中的向量。“完成dizzystar的答案”---谢谢。我没有指出的一点是,根据我的经验,复发通常可以减少为更干净的东西。探索Clojure需要相当长的时间,其中的挑战是始终寻找替代品。改编的“qextend助手”是错误的。“循环”是多余的:该函数是“re”的合法且惯用的目标是的,函数是重现的合法目标。重点是重现函数不应该是第一件要达到的事情。至于循环,它只是为了让他开始。我更喜欢让人来决定改进的方向。我甚至在回答中说,这不是好的Clojure。
    (defn qextend [n partial-sol-list]
      (if (seq partial-sol-list)
        (lazy-cat (qextend-helper n 1 (first partial-sol-list) [])
                (qextend n (rest partial-sol-list)))
        nil))
    
    => (sol-count 11)
    2680