这个clojure prime seq出了什么问题?

时间:2012-07-11 11:44:18

标签: clojure lazy-sequences

我无法弄清楚为什么惰性素数序列的这个定义会导致非终止。我得到的堆栈跟踪不是很有帮助(我对clojure的一个抱怨是钝的堆栈跟踪)。

(declare naturals is-prime? primes)

(defn naturals
  ([] (naturals 1))
  ([n] (lazy-seq (cons n (naturals (inc n))))))

(defn is-prime? [n]
  (not-any? #(zero? (rem n %))
                (take-while #(> n (* % %)) (primes))))

(defn primes
  ([] (lazy-seq (cons 2 (primes 3))))
  ([n] (let [m (first (filter is-prime? (naturals n)))]
         (lazy-seq (cons m (primes (+ 2 m)))))))

(take 10 (primes)) ; this results in a stack overflow error

3 个答案:

答案 0 :(得分:0)

问题是要知道计算“素数”函数你正在使用“是素数”吗?函数,然后计算“是素数?”函数你使用“(素数)”,因此堆栈溢出流量。

所以要计算“(素数3)”,你需要计算“(首先(过滤器是素数?(自然3)))”,这将称为“(is-prime?1)” ,它称为“(素数)”,它又称为“(素数3)”。换句话说,你在做:

user=> (declare a b)
#'user/b
user=> (defn a [] (b))
#'user/a
user=> (defn b [] (a))
#'user/b
user=> (a)
StackOverflowError   user/b (NO_SOURCE_FILE:1)

要了解如何生成素数:Fast Prime Number Generation in Clojure

答案 1 :(得分:0)

让我们开始执行primes,我们会神奇地意识到一个seq只是为了清楚。我会忽略naturals,因为它是正确的懒惰:

 > (magically-realise-seq (primes))
=> (magically-realise-seq (lazy-seq (cons 2 (primes 3))))
=> (cons 2 (primes 3))
=> (cons 2 (let [m (first (filter is-prime? (naturals 3)))]
             (lazy-seq (cons m (primes (+ 2 3))))))
=> (cons 2 (let [m (first (filter
                            (fn [n]
                              (not-any? #(zero? (rem n %))
                                            (take-while #(> n (* % %)) (primes))))) 
                            (naturals 3)))]
             (lazy-seq (cons m (primes (+ 2 3))))))

我已将is-prime?替换为最后的fn - 您可以看到primes将再次被调用,并至少实现一次为take-while拉出元素。这将导致循环。

答案 2 :(得分:0)

我认为问题是,你在构建它之前尝试使用(素数)。

像这样更改is-prime?可解决问题:

(defn is-prime? [n]
     (not-any? #(zero? (rem n %))
               (take-while #(>= n (* % %)) (next (naturals)))))

(注意,我已将>更改为>=,否则它会给出4是素数。它仍然表示1是素数,这不是真的,如果你可能会导致问题在其他地方使用is-prime?