lazy-seq中的OutOfMemoryError

时间:2013-01-12 15:31:54

标签: clojure

  

可能重复:
  Recursive function causing a stack overflow

完成示例lazy-seq here

(defn sieve [s]
  (cons (first s)
        (lazy-seq (sieve (filter #(not= 0 (mod % (first s)))
                             (rest s))))))

如果我尝试生成超过几千个素数,我会得到一个OutOfMemoryError。根据我的研究(但我对clojure很新),我怀疑这可能是班级“抓住头”的问题,但无法弄清楚为什么会这样或者如何补救。如何更改此函数,以便在生成大量素数时不会耗尽内存?

2 个答案:

答案 0 :(得分:2)

您可以在不创建延迟序列的情况下使用版本。它工作得更快,更便宜:

 (defn sieve* [res s]
      (if (empty? s)
        res
        (recur (conj res (first s))
               (filter #(not= 0 (mod % (first s)))
                       (rest s)))))

(defn sieve [n]
  (sieve* [] (range 2 n)))

(sieve 10000)
=> [2 3 5 7 11 13 17 ... 9941 9949 9967 9973]

这是更高效的版本:

(defn sieve* [res n maxn]
  (if (> n maxn)
    res
    (if (some #(= 0 (mod n %))
              (take (round (sqrt (count res))) res))
      (recur res (inc n) maxn)
      (recur (conj res n) (inc n) maxn))))

(defn sieve [n]
  (sieve* [] 2 n))

(last (sieve 1000000))
=> 999983

更新。非常快/便宜的懒人版

(defn primes-seq* [primes]
  (let [last-prime (last primes)]
    (cons last-prime
          (lazy-seq
           (primes-seq*
            (conj primes
                  (first (let [compare-primes
                               (take (round (sqrt (count primes)))
                                     primes)]
                           (drop-while (fn [n]
                                         (some #(= 0 (mod n %))
                                               compare-primes))
                                       (iterate inc (inc last-prime)))))))))))


(def primes-seq (primes-seq* [2]))

(last (take 50000 primes-seq))
=> 611953

答案 1 :(得分:1)

给定的算法通过"记住"所有以前的素数,所以如果你继续走得足够长的话,你将要筹码。

以下效果可能效率较低,但不会耗尽内存(从4clojure解决方案改为#116):

(defn prime-seq []
  (letfn [(is-prime [x]
            (not (some #(= (rem x %) 0) (range 2 x))))]
    (filter is-prime (range))))

(take 20 (prime-seq))
;=> (0 1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61)
(nth (prime-seq) 10000)
;=> 104723