Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.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:避免Erathosthene筛中的堆栈溢出?_Clojure_Primes_Tail Recursion_Sieve Of Eratosthenes - Fatal编程技术网

Clojure:避免Erathosthene筛中的堆栈溢出?

Clojure:避免Erathosthene筛中的堆栈溢出?,clojure,primes,tail-recursion,sieve-of-eratosthenes,Clojure,Primes,Tail Recursion,Sieve Of Eratosthenes,以下是我在Clojure中对Erathosthene筛的实现(基于关于streams的SICP课程): 现在,当我取前100个素数时,一切都好了: (take 100 primes) 但是,如果我尝试获取前1000个素数,程序会因为堆栈溢出而中断。 我想知道,是否有可能以某种方式将函数筛更改为尾部递归,并且仍然保留算法的“流线” 有什么帮助吗?首先,这不是埃拉托斯坦的筛子。。。详情见我的评论 第二,为投票结果接近表示歉意,因为你的问题与我所指的问题并不完全相同。。。我的错 解释正在发生的事情

以下是我在Clojure中对Erathosthene筛的实现(基于关于streams的SICP课程):

现在,当我取前100个素数时,一切都好了:

(take 100 primes)
但是,如果我尝试获取前1000个素数,程序会因为堆栈溢出而中断。 我想知道,是否有可能以某种方式将函数筛更改为尾部递归,并且仍然保留算法的“流线”


有什么帮助吗?

首先,这不是埃拉托斯坦的筛子。。。详情见我的评论

第二,为投票结果接近表示歉意,因为你的问题与我所指的问题并不完全相同。。。我的错

解释正在发生的事情 当然,区别在于您正试图构建一个增量筛选,其中
remove
调用的工作范围是无限的,因此不可能仅围绕它包装
doall
。解决方案是实施一个“真正的”增量国有企业,这是我最近经常联系到的一篇文章——梅丽莎E.奥尼尔的

克里斯托夫·格兰德(Christophe Grand)已经编写了一个特别漂亮的Clojure筛实现,可以让所有感兴趣的人都欣赏它。强烈推荐阅读

至于问题的来源,我最初认为你的问题是一个重复的问题,其中包含对你有用的解释:见和。再一次,为草率的投票结束感到抱歉

为什么尾部递归没有帮助 由于问题特别提到将筛选函数tail recursive作为可能的解决方案,因此我想在这里说明:转换惰性序列的函数通常不应该是tail recursive

这是一个需要记住的非常重要的一点,它让许多没有经验的Clojure(或Haskell)程序员感到困惑。原因是,必然的尾部递归函数只有在“准备就绪”——即在计算的最后——时才返回其值。(迭代过程可以在任何特定迭代结束时返回一个值或继续进行下一次迭代。)相反,生成惰性序列的函数应该立即返回一个惰性序列对象,该对象封装了一些代码位,可以要求这些代码在需要时生成序列的开头或结尾


因此,堆叠惰性转换问题的答案不是使任何东西都具有尾部递归性,而是合并转换。在这种特殊情况下,可以根据优先级队列或映射(请参阅以获取详细信息),通过使用自定义方案融合过滤操作来获得最佳性能。

另请参阅,其中包括对您实现的算法实际上不是SoE的原因的讨论(另外还有一个链接,链接到《函数式编程杂志》(Journal of Functional Programming)上的一篇文章,该文章详细解释了这种差异及其对算法复杂性的影响)。作为旁注,出于同样的原因,SICP筛也会在某个点爆炸,尽管某些方案实现默认情况下可能有更深的堆栈。这本身并不是不可避免的,但随着流操作的实现,如果您可能需要更改,则更容易切换到不同的筛方案生成许多素数。
(take 100 primes)