Clojure原子将向量转换为列表?

4

我想使用一个Clojure向量在一个原子中建模一个有状态的FIFO(从末尾推入,从开头弹出)。尝试过:

(def stack (atom []))

然后按照以下方式push:
(swap! stack #(conj % 1))
(swap! stack #(conj % 2))

期望的
[1 2]

但是获取
(2 1)

不是什么大问题,这意味着我必须反转(atom)的值(O(n)),以便按照我推送它们的顺序获取项目(例如,将命令流发送到虚拟机的顺序)。不过,这还是有些出乎意料的。
是否有一个clojure.core先进先出队列可以打包到一个atom中?我想到了priority-map,但似乎有点过头了。Clojuredocs.org上swap!的示例使用列表或映射,不太符合我的要求。通过谷歌搜索"FIFO Clojure",我找到了很多示例,但有些有点复杂,例如clojure.core.cache(类似于映射而不是向量); amalloy的ring-buffer(外部依赖项)。我正在寻找一些真正简单明了的东西。我没有在StackOverflow的自动建议中看到答案。
1个回答

5

在代码的更广泛背景下,有些事情不太对劲;我假设您拥有比您发布的示例更多的内容?

这是我的REPL中的结果和我的期望:

user=> (def stack (atom []))
#'user/stack
user=> (swap! stack #(conj % 1))
[1]
user=> (swap! stack #(conj % 2))
[1 2]
user=> @stack
[1 2]

使用向量时,项目会添加到集合的末尾。你看到的结果看起来像是 stack 是一个列表而不是一个向量,例如添加到前面:

user=> (def stack (atom '()))
#'user/stack
user=> (swap! stack #(conj % 1))
(1)
user=> (swap! stack #(conj % 2))
(2 1)
user=> @stack
(2 1)

我在想,也许你的代码中定义了一个列表,而不是向量。


这段代码涉及到了一系列的推入和弹出测试。看起来当我从向量堆栈中弹出最后一个项目时,原子会留下一个空列表而不是一个空向量。随后的推入操作将连接到该列表而不是向量。在我的弹出函数中修复很容易 --- 如果最后一个弹出操作清空了堆栈,则将其放回一个空向量即可。 - Reb.Cabin
1
不,(pop [1])[]。那不是你的问题。现在,如果你曾经调用 restseq,那么它可能会变成一个列表。 - amalloy
我写了自己的(愚蠢,错误的)pop函数,调用了(partial drop 1)并无意中进行了转换。现在改用内置的pop函数。 - Reb.Cabin
好的,内置的 pop 从向量的末尾弹出,因此我认为它在最直接的用法中实现了 LIFO。当原子序列为空时,我暂时使用 (swap! fifo (fn [_] [])) - Reb.Cabin
4
如果你想要一个队列而不是栈,只需使用内置的队列 clojure.lang.PersistentQueue - amalloy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接