【问题标题】:idiomatic lazy atoms in clojureclojure 中惯用的惰性原子
【发布时间】:2025-12-28 15:40:11
【问题描述】:

我正在玩一些clojure 中的原子。我有一个atom 指向lazy-seq。在另一段代码中,我想将原子的值更新为对序列执行next 的结果,但鉴于swap!reset! 都返回更新的值,执行永远不会结束。 我发现我总是可以将对swap!reset! 的调用包装在一个do 语句中,然后返回nil,但我想知道这是多么地道,或者是否有替代解决方案。

不终止:

(def x (atom (range)))
(swap! x next)

终止

(def x (atom (range)))
(do (swap! x next) nil)
(first @x) ;1
(do (swap! x next) nil)
(first @x) ;2

【问题讨论】:

    标签: clojure atomic lazy-sequences


    【解决方案1】:

    这里的问题不在于 Clojure,而在于您使用的 repl。对swap! 的调用工作得很好,这是repl 试图打印出结果,但它不能,因为序列永远不会结束。您可以通过(set! *print-length* 10) 设置 Clojure 的内置 repl 打印的项目数。但是,如果您有其他执行不同打印逻辑的 REPL 中间件,这并不总是有效。

    关于“这样做的惯用方式是什么”这个话题,我会给你两个选择:

    1. 将您对swap! 的调用封装在一个返回某些内容的函数中 不同。
    2. 或者,在上述用例中,将一个整数放入原子中,然后使用(swap! x inc) 获取下一个整数。

    【讨论】:

    • 谢谢!这为我的问题提供了解决方案。我想根据您的第一个选项将调用包装在 do 语句中应该被视为惯用的
    【解决方案2】:

    好吧,你可以结合交换!首先:

    (def x (atom (range)))
    (first (swap! x next))
    (first (swap! x next))
    

    但我不确定您为什么要包装无限列表,然后每次只使用第一个值。似乎这样会更简单并产生相同的结果:

    (def x (atom 0))
    (swap! x inc)
    (swap! x inc)
    

    【讨论】:

    • 感谢您的回答,实际上这是我的代码的简化版本。实际上,我不仅有范围,还有另一种惰性序列,其中下一个值并不总是前一个值加一。