作为序言,我在 Windows 7(64 位)上,使用clooj作为我的 IDE 运行 Java 版本 6(更新 33)。我没有尝试在任何其他系统中重现我的问题。我对 Clojure 有经验,但对 Java 完全没有。
我试图解决的整个问题描述起来很长,但归结为:假设我想做一个宏,它接受一个参数,一个关联映射,并返回一个元素的向量保留其顺序的地图。
=>(defmacro vectorize-a-map
[associative-map]
(vec associative-map))
=>#'ns/vectorize-a-map
=>(vectorize-a-map {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8}
=>[[:a 1] [:b 2] [:c 3] [:d 4] [:e 5] [:f 6] [:g 7] [:h 8]]
那行得通,但是向地图添加另一个元素并且顺序混乱了...
=>(vectorize-a-map {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9}
=>[[:a 1] [:c 3] [:b 2] [:f 6] [:g 7] [:d 4] [:e 5] [:i 9] [:h 8]]
我相信我已经发现了为什么会发生这种情况。似乎任何具有 8 个或更少元素的东西都被实例化为 PersistentArrayMap,这正是我想要的,因为据我所知,这个类保留了顺序。但是,任何具有 9 个或更多元素的东西都会被实例化为不保留顺序的 PersistentHashMap。
=>(type {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8}
=>clojure.lang.PersistentArrayMap
=>(type {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9}
=>clojure.lang.PersistentHashMap
我希望我的宏能够获取任何大小的关联地图,所以这是一个问题。我尝试过类型提示、解构绑定、列表理解和取消引用拼接,但都没有成功。要画出来,以下任何方法都不起作用:
(defmacro vectorize-a-map
[^clojure.lang.PersistentArrayMap associative-map]
(vec associative-map))
(defmacro vectorize-a-map
[[& associative-map]]
(vec associative-map))
(defmacro vectorize-a-map
[associative-map]
(vec
(for [x associative-map]
x)))
(defmacro vectorize-a-map
[associative-map]
`(vector ~@associative-map))
对于我提出的这个玩具问题,我意识到我可以像这样简单地编写我的宏,并完全避免这个问题:
=>(defmacro vectorize-kvs
[& elements]
(vec (map vec (partition 2 elements))))
=>#'ns/vectorize-kvs
=>(vectorize-kvs :a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9)
=>[[:a 1] [:b 2] [:c 3] [:d 4] [:e 5] [:f 6] [:g 7] [:h 8] [:i 9]]
然而,对于我试图解决的实际问题(我还没有涉及),宏能够采用关联映射是很重要的(尽管不是 100% 必要)。似乎我正在寻找如何在任何事情发生之前将参数转换为 PersistentArrayMap 。可能还有其他一些我根本没有考虑或不知道的解决方案的途径。
我已经研究了我所知道的最好的方法,但还没有发现任何有用的东西。有人有什么想法/建议吗?