Clojure 中惯用的惰性原子

idiomatic lazy atoms in clojure

我在 Clojure 中玩了一下原子。我有一个 atom 指向 lazy-seq。在另一段代码中,我想将原子的值更新为对序列执行 next 的结果,但考虑到更新后的 swap!reset! return价值执行永无止境。 我发现我总是可以在 do 语句中包装对 swap!reset! 的调用,然后是 return 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

好吧,你可以结合交换!第一个:

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

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

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

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

关于"what is the idiomatic way of doing this"这个话题,我给你两个选择:

  1. 将对 swap! 的调用包装在一个 returns 函数中 不同。
  2. 或者,在上面的用例中,将一个整数放入原子中,然后使用 (swap! x inc) 获取下一个整数。