Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 无限序列的延迟序列和堆栈溢出_Clojure_Lazy Evaluation_Lazy Sequences - Fatal编程技术网

Clojure 无限序列的延迟序列和堆栈溢出

Clojure 无限序列的延迟序列和堆栈溢出,clojure,lazy-evaluation,lazy-sequences,Clojure,Lazy Evaluation,Lazy Sequences,我试图向非FP程序员展示惰性序列或惰性计算的重要性。我编写了这个“黄金一代”的实现来展示这个概念: (defn primes-gen [sieve] (if-not (empty? sieve) (let [prime (first sieve)] (cons prime (lazy-seq (primes-gen (filter (fn [x]

我试图向非FP程序员展示惰性序列或惰性计算的重要性。我编写了这个“黄金一代”的实现来展示这个概念:

(defn primes-gen [sieve]
  (if-not (empty? sieve)
    (let [prime (first sieve)]
      (cons prime
            (lazy-seq (primes-gen
                       (filter (fn [x]
                                 (not= 0 (mod x prime)))
                               (rest sieve))))))))

;;;;; --------- TO SHOW ABOUT THE LAZY-THINGS 
;; (take 400 (primes-gen (iterate inc 2)))
;; (take 400 (primes-gen (range 2 1000000000000N)))
然而,如果我给
take
任何更大的值,就会得到堆栈溢出异常

堆栈是:

user> (pst)
StackOverflowError 

    clojure.core/range/fn--4269 (core.clj:2664)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.RT.seq (RT.java:484)
    clojure.core/seq (core.clj:133)
    clojure.core/filter/fn--4226 (core.clj:2523)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.RT.seq (RT.java:484)
    clojure.core/seq (core.clj:133)
看来
filter
thunks正在累积。 但是如果执行
(doall(filter…
),那么我将无法处理无限序列,即
(take 1000(primes gen(iterate inc 2))
将不再工作


正确的方法是什么?

您的分析非常准确:您嵌套的过滤器太多了。 您应该修改prime gen以获得两个参数:一组已知的prime和候选者。 请参阅我的博客,了解有关的其他想法

更新: 因此,您将过滤器堆叠在过滤器之上,并且在某些情况下,当您想要获取新候选时,堆栈太大

您必须将所有过滤器合并为一个(或合理数量的)过程。这里很简单,因为过滤器非常同质。因此,我将过滤器堆栈替换为包含已知素数的集合

(defn primes-gen
 ([candidates] (primes-gen candidates []))
 ([candidates known-primes]
  (lazy-seq ; I prefer having the lazy-seq up here
    (when-first [prime candidates] ; little known macro
      (let [known-primes (conj known-primes prime)]
        (cons prime
          (primes-gen
            (drop-while (fn [n] (some #(zero? (mod n %)) known-primes)) candidates)
             known-primes)))))))

可能的解决方案之一是将生成器函数移动到lazy seq中。例如(取自):

(def primes
(康卡特)
[2 3 5 7]
(续)
(让[素数]从
(fn素数来自[n[f&r]]
(如果(某些#)(零)(rem n%))

(花点时间#)(小点:宁愿选择
(如果(序列筛))
而不是
(如果不是(空筛)…)
@amalloy标记的问题根本不是这个问题的重复:它处理有限序列,而这个问题专门询问无限序列。投票重新打开,希望你也这样做。@WillNess同意。这是相同的基本问题,但当你需要为一个I工作时,我作为的重复关闭的问题的答案不起作用nfinite输出。供未来观众参考:不像我想象的那样是重复的。@amalloy感谢您的快速操作!:)很抱歉,我不能理解你的算法。实际上我更感兴趣的是如何解决这个thunk问题。对素数算法也不太感兴趣。你能在你的代码中解释一下你是如何解决这个thunk问题的吗?在这种特殊情况下,算法更改(到真正的sieve impl)是“去thunk”的策略。请参阅我的更新,以了解与原始代码的不太严重的差异。哦!!!看看它。。我发现如果我不在
lazy seq
中使用lazy函数,那么我就不会有thunks问题。这就是我们使用
(doall
不幸的是懒惰的人..但是你证明了,我们可以在更好地理解问题和语言的情况下,在无限序列和无thunks两个方面取得最佳效果..谢谢。。
(def primes
  (concat
   [2 3 5 7]
   (lazy-seq
    (let [primes-from
          (fn primes-from [n [f & r]]
            (if (some #(zero? (rem n %))
                      (take-while #(<= (* % %) n) primes))
              (recur (+ n f) r)
              (lazy-seq (cons n (primes-from (+ n f) r)))))
          wheel (cycle [2 4 2 4 6 2 6 4 2 4 6 6 2 6  4  2
                        6 4 6 8 4 2 4 2 4 8 6 4 6 2  4  6
                        2 6 6 4 2 4 6 2 6 4 2 4 2 10 2 10])]
      (primes-from 11 wheel)))))