我在Clojure中实现了Eratosthenes的筛子:
(defn sieve [n]
(loop [last-tried 2 sift (range 2 (inc n))]
(if
(or (nil? last-tried) (> last-tried n))
sift
(let [filtered (filter #(or (= % last-tried) (< 0 (rem % last-tried))) sift)]
(let [next-to-try (first (filter #(> % last-tried) filtered))]
(recur next-to-try filtered))))))
对于较大的n
(如20000),它以堆栈溢出结束。为什么尾部呼叫消除不在这里工作?如何解决?
答案 0 :(得分:12)
答案 1 :(得分:2)
如果你看一下回溯
(try
(sieve 200000)
(catch java.lang.StackOverflowError e
(.printStackTrace e)))
它看起来像这样:
...
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:56)
at clojure.lang.RT.seq(RT.java:440)
at clojure.core$seq__4176.invoke(core.clj:103)
at clojure.core$filter__5033$fn__5035.invoke(core.clj:1751)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:56)
...
太多的过滤器导致溢出,而不是循环。
不幸的是,我没有看到明显的解决方案。
答案 2 :(得分:0)
我是Michal Marczyk关于检查cgrande美丽增量SoE的评论。我做了一些非常原始的基准测试并将它们放在http://clojure.roboloco.net/?p=100,以便那些对懒惰素发生器性能感到好奇的人。