(defn insert [s k]
(let [spl (split-with #(< % k) s)]
(concat (first spl) (list k) (last spl))))
(defn insert-sort [s]
(reduce (fn [s k] (insert s k)) '() s))
(insert-sort (reverse (range 5000)))
抛出堆栈超过流错误。我在这里做错了什么?
答案 0 :(得分:3)
与Recursive function causing a stack overflow相同的问题。 Concat构建了一堆嵌套的延迟序列,如(concat(concat ...)))而不做任何实际的工作,然后当你强制第一个元素时concat
s必须立即解决,吹掉堆栈。
答案 1 :(得分:2)
您的reduce
每次都会创建新列表。
我的实施:
(defn- insert [el seq]
(if (empty? seq) (cons el seq)
(if (< el (first seq)) (cons el seq)
(cons (first seq) (insert el (rest seq))))))
(defn insertion-sort
([seq sorted]
(if (empty? seq) sorted
(recur (rest seq) (insert (first seq) sorted))))
([seq]
(insertion-sort seq nil)))
答案 2 :(得分:1)
正如主要答案所示,名单连字是罪犯。使用该列表作为输入调用“doall”将导致ISeq:
;;insertion sort helper
(defn insert [s k]
;;find the insert point
(let [spl (split-with #(< % k) s)
ret (concat (first spl) (list k) (last spl))]
(doall ret)))
;;insertion sort
(defn insert-sort [s]
(reduce (fn [s k] (insert s k)) '() s))
但等等......序列是否仍然是懒惰的?
以下有关上述代码的黑客表明序列确实仍然是懒惰的!
;;insertion sort helper
(defn insert [s k]
;;find the insert point
(let [spl (split-with #(< % k) s)
ret (concat (first spl) (list k) (last spl))
ret2 (doall ret)
_ (println "final " (.getClass ret2))]
ret2))
;;insertion sort
(defn insert-sort [s]
(reduce (fn [s k] (insert s k)) '() s))
所以,如果列表仍然是懒惰的,为什么使用doall修复了什么?
“doall”函数不能保证返回“非懒惰”列表,而是保证它返回的列表将通过完整的评估进行评估。
因此,问题的本质是多个函数调用,懒惰肯定与原始问题中代码的这个方面有关,但它不是溢出的“主要”来源。