Clojure:避免埃拉托斯特尼筛中的堆栈溢出?

2024-04-17

这是我在 Clojure 中实现的埃拉托斯特尼筛法(基于 SICP 流课程):

(defn nats-from [n]
  (iterate inc n))

(defn divide? [p q]
  (zero? (rem q p)))

(defn sieve [stream]
  (lazy-seq (cons (first stream)
            (sieve (remove #(divide? (first stream) %) 
               (rest stream))))))

(def primes (sieve (nats-from 2)))

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

(take 100 primes)

但是,如果我尝试采取前 1000 个素数,程序因堆栈溢出而中断。 我想知道是否有可能以某种方式改变函数筛以成为尾递归,并且仍然保留算法的“流”?

有什么帮助吗???


首先,这不是埃拉托斯特尼筛......有关详细信息,请参阅我的评论。

其次,对势均力敌的投票表示歉意,因为你的问题并不是我指出的问题的实际重复......我的错。

对正在发生的事情的解释

当然,区别在于您正在尝试构建一个增加的筛子,其中的范围remove调用工作是无限的,因此不可能只包装一个doall周围。解决方案是实施我最近经常链接到的论文中的“真正的”增量 SoE 之一——Melissa E. O'Neill 的论文真正的埃拉托色尼筛子 http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf.

Christophe Grand 编写了这种类型的特别漂亮的 Clojure sieve 实现,并且可以使用here http://clj-me.cgrand.net/2009/07/30/everybody-loves-the-sieve-of-eratosthenes/为了引起所有可能感兴趣的人的钦佩。强烈推荐阅读。

至于问题的根源,我最初认为你的问题是重复的,其中包含对你有用的解释:参见here https://stackoverflow.com/questions/2980587/clojure-tail-recursive-sieve-of-eratosthenes and here https://stackoverflow.com/questions/2946764/recursive-function-causing-a-stack-overflow。再次对仓促结束的投票表示歉意。

为什么尾递归没有帮助

由于问题特别提到将筛选函数尾递归作为可能的解决方案,我想我应该在这里解决这个问题:一般来说,转换惰性序列的函数不应该是尾递归的.

这是需要牢记的非常重要的一点,也是许多没有经验的 Clojure(或 Haskell)程序员会犯的错误。原因是尾递归函数只有在“准备好”时(在计算的最后)才返回其值。 (迭代过程可以在任何特定迭代结束时返回一个值或继续进行下一次迭代。)相比之下,生成惰性序列的函数应该立即返回一个惰性序列对象,该对象封装了一些代码位可以在需要时要求生成序列的头部或尾部。

因此,堆叠惰性转换问题的答案不是使任何内容成为尾递归,而是合并转换。在这种特殊情况下,可以通过使用自定义方案来融合基于优先级队列或映射的过滤操作来获得最佳性能(请参阅上述文章 http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf了解详情)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Clojure:避免埃拉托斯特尼筛中的堆栈溢出? 的相关文章

随机推荐

  • 自定义WinForms按钮不改变图像?

    我创建了一个自定义按钮 名为 AcceptButton 继承自 System Windows Forms Button 在构造函数上 我设置了一些属性 但最重要的是一个图像 绿色复选标记 如下所示 this Image Proyecto C
  • 如何使用 Razor 将部分视图视图模型项目保存在主视图视图模型中?

    这可能是一个棘手的问题 但就这样吧 假设我有一个主视图 我们称之为MainView cshtml Now MainView cshtml有一个专用的 ViewModel 称为MainViewModel cs它保存一个变量Model Exam
  • Corba 事件客户端 ETIMEDOUT

    我使用omniOrb 和Python 构建了一个CORBA 事件服务客户端 我在使用 Java 客户端时遇到了同样的问题 我非常确定我遇到了与这篇文章相同的事情 因为我的 strace 看起来非常相似 但他没有确切解释他是如何修复它的 Ja
  • 对于 Buffer 等运算符来说,打开和关闭边界的含义是什么?

    我不明白需要打开或关闭边界的 Buffer 运算符的重载 我指的重载是 public static IObservable
  • 如何使用 python 和 Opencv 计算图像中的点数?

    I want to count number of dots in an image The image looks like 我参考了这个 SOF 链接计算图像中的彩色点 https stackoverflow com questions
  • 即使使用stream_set_blocking,PHP SSH2流内容仍为空?

    我正在开发一个工具 它使用 PECL SSH2 扩展通过 SSH2 从远程主机读取 iptables 配置 我能够成功连接到主机 进行身份验证并执行命令 我遇到的问题是有时该流不包含任何数据 Load the current firewal
  • TwoSum 算法:如何改进?

    我想做一个算法并发现这个问题leetcode http www leetcode com 给定一个整数数组 找到两个数字 使它们加起来等于特定的目标数字 函数twoSum 应返回两个数字的索引 以便它们相加达到目标 其中index1 必须小
  • Jython,仅使用 Java 中的 Python 方法?

    阅读和使用时本文 http www rexx com dkuhlman jython course 03 html example the jython classes它假设我们有一个完整的对象定义 包含类和从 python 到 java
  • 查找日期的两个周期之间重叠的天数

    我有两个表 每个表都保存日期期间 从 date1 到 date2 我将在表1和表2中查找两个日期期间之间的重叠天数 Example table1 id FromDate ToDate 1 2000 01 01 2000 02 04 2 20
  • 映射减少计数示例

    我的问题是关于mapreduce programming in java 假设我有 WordCount java 示例 一个标准mapreduce program 我希望map函数收集一些信息 并返回形成如下的reduce函数map
  • 如何从单独的文件下载用于 cmake 中交叉编译的工具链?

    我有一个项目 根目录中有一个 CMakeLists txt 文件 该项目在 Linux 和 OSX 上编译得很好 现在我想为 MIPS OpenWRT 交叉编译它 我想尽可能地自动化它 所以我将使用以下代码来下载工具链并设置编译器变量 Ex
  • 停止并重新启动计时器

    我想停止这个计时器 然后从停止的地方重新启动它 secondsTimer Timer scheduledTimer timeInterval 1 0 target self selector selector addSeconds user
  • 覆盖 FILE_LOG_PATTERN (如果可能的话每个环境)

    我想覆盖 Spring Boot 的默认文件和控制台日志模式以包含一些自定义 MDC 字段 有没有一种简单的方法可以使用application properties yaml 如果没有的话 这将是一个很好的功能 否则我可能不得不复制 Boo
  • 比较当前文件版本和上一个远程存储库

    如何区分我的工作文件版本与远程存储库中的某些先前版本 假设我今天拉取 对本地副本执行 6 8 次提交 然后想要查看我的最新工作版本 给定文件 与远程或任何其他版本上的最新版本之间的差异 要查看 最新工作版本 我将其作为您的工作副本 之间的差
  • 使用 sharekit 在 Facebook 上添加图像和描述

    我正在使用 sharekit 在 Facebook 上分享文本 我想在文本附近添加一张图片 如下图所示 知道如何做到这一点吗 还有其他合适的库 例如 sharekit 吗 谢谢 将 og image 元标记添加到 head html 块中
  • 如何获取使用 AngularDart 的路线?

    这是我的代码 import package angular angular dart class AppModule extends Module AppModule type AppController type LoginControl
  • Biopython无法直接访问异质残基

    我可以使用以下方法直接获取蛋白质 1n31 的残基 residue structure 0 A 100 然而 当我尝试访问异质残基时 例如 residue structure 0 A 2003 我收到错误消息 File
  • 顺序订阅可观察数组

    在这里 我用过forkJoin从 rxjs 并行订阅可观察数组 但我想一一订阅 最好的解决方案是什么 下面是我的代码 var observables Observable forkJoin observables subscribe gt
  • 从 Vaadin 8 Grid 获取列表

    Problem 我有一个 Vaadin 8 Grid 但我找不到提取其中项目的方法 描述 从网格开始 Grid
  • Clojure:避免埃拉托斯特尼筛中的堆栈溢出?

    这是我在 Clojure 中实现的埃拉托斯特尼筛法 基于 SICP 流课程 defn nats from n iterate inc n defn divide p q zero rem q p defn sieve stream lazy