Clojure中的神秘无限循环

时间:2013-02-16 04:22:23

标签: clojure infinite-loop

我正在编写一个Clojure函数,通过有向图上的深度优先搜索执行拓扑排序,对于某些输入,它不会终止。它使用loop-recur,但是我没有看到在重复的参数中使用任何惰性序列,这似乎是无限循环最常见的罪魁祸首。我在纸上运行程序以获取下面的示例输入,它们似乎都运行良好。

(require '[clojure.set :as set])

;graph is a hash map, keys are nodes, vals are 
;collections of other nodes that node points to
(defn DFSsort [graph]
  (loop [stack `(~(ffirst graph)),
         visited '()]
    (let [unvisited (set/difference (set (keys graph))
                                    (set visited)),
          node (peek stack), 
          neigh (graph node)]
      (if (empty? stack)
        (if (seq unvisited)
          (recur (conj stack (first unvisited))
                 visited)
          visited) ; return
        (if (seq (set/difference (set neigh) (set visited)))    
          (if (not-any? (partial = (first neigh)) stack)
            (recur (conj stack (first neigh))
                   visited)
            "Cycle detected!") ; abort
          (recur (pop stack)
                 (conj visited node)))))))

(DFSsort {1 [2 3], 2 [3], 3 []})
;=> (1 2 3) 

(DFSsort {1 [2 3], 2 [], 3 []})
;Infinite loop

(DFSsort {1 [2 3], 2 [], 3 [2]})
;Infinite loop

1 个答案:

答案 0 :(得分:1)

当调用recur时,你正在使用当前节点的第一个邻居,而不是第一个未访问的邻居。对于节点1,您始终将节点2添加到堆栈中。

试试这个:

(defn DFSsort [graph]
  (loop [stack `(~(ffirst graph)),
         visited '()]
    (println stack visited)
    (let [unvisited (set/difference (set (keys graph))
                                    (set visited)),
          node (peek stack), 
          neigh (graph node)
          unseen-neigh (seq (set/difference (set neigh) (set visited)))]
      (if (empty? stack)
        (if (seq unvisited)
          (recur (conj stack (first unvisited))
                 visited)
          visited) ; return
        (if unseen-neigh
          (if (not-any? (partial = (first unseen-neigh)) stack)
            (recur (conj stack (first unseen-neigh))
                   visited)
            "Cycle detected!") ; abort
          (recur (pop stack)
                 (conj visited node)))))))