我正在尝试实现一个简单的有状态转换,该转换器可以计算项目数量(使用 ClojureScript)
(defn stateful-counter []
(fn [xf]
(let [counter (atom 0)]
(fn
([] (xf))
([result]
(xf (xf result @counter)))
([result _]
(swap! counter inc)
result)))))
当我对此序列运行此代码时,我得到以下输出
(into [] (stateful-counter) (range 5))
[5]
这正是我期望的。
当我将此代码运行在 core.async 通道上时,我得到一个无限的包含数字 5 的序列
(go (println
(<! (let [c (async/chan 1 (stateful-counter))]
(async/onto-chan! c (range 5))
(async/into []
(async/take 10 c))))))
[5 5 5 5 5 5 5 5 5 5]
如果我不使用 (async/take 10 _),似乎会出现无限循环。预期的结果是 [5]。
我还尝试使用 net.cgrand.xforms/count 从 xforms 库,并得到相同的不意外结果
(go (println
(<! (let [c (async/chan 1 xforms/count)]
(async/onto-chan! c (range 5))
(async/into []
(async/take 10 c))))))
我原本以为我在有状态的计数器实现中犯了实现错误导致了循环。但是我对 xforms/count 产生相同(不意外)的结果感到困惑。
这是一段 ClojureScript 代码片段,但我已经能够用 Clojure 产生相同的不预期结果。
有人能帮我理解为什么在有状态的转换器应用在 core.async 通道上会得到无限序列吗?
编辑:我也在 Clojure 中看到了相同的不预期行为。