【问题标题】:What's wrong with this clojure prime seq?这个clojure prime seq有什么问题?
【发布时间】:2012-07-11 00:39:55
【问题描述】:

我不明白为什么这个惰性素数序列的定义会导致不终止。我得到的堆栈跟踪不是很有帮助(我对 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

【问题讨论】:

    标签: clojure lazy-sequences


    【解决方案1】:

    让我们开始执行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】:

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

      所以要计算“(primes 3)”,你需要计算“(first (filter is-prime?(naturals 3)))”,它会调用“(is-prime?1)” ,它调用“(primes)”,而后者又调用“(primes 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

      【讨论】:

        【解决方案3】:

        我认为问题在于,您在 (primes) 已经构建之前尝试使用它。

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

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

        (请注意,我已将 > 更改为 >=,否则它会认为 4 是素数。它仍然说 1 是素数,这是不正确的,如果您使用 is-prime? 可能会导致问题其他地方。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-17
          • 2012-05-26
          • 2021-08-20
          相关资源
          最近更新 更多