Macro Clojure que conservará a ordem dos mapas associativos
Para prefácio, estou no Windows 7 (64 bits), executando o Java versão 6 (atualização 33) usandoclooj como meu IDE. Eu não tentei reproduzir meu problema em nenhum outro sistema. Eu sou experiente com o Clojure, mas não com o Java.
A totalidade do problema que estou tentando resolver é demorada para descrever, mas tudo se resume a isto: digamos que eu gostaria de fazer uma macro que pega um argumento, um mapa associativo e retorna um vetor dos elementos do mapa com a sua ordem conservada.
=>(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]]
Isso funciona, mas adicione outro elemento ao mapa e a ordem atrapalha ...
=>(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]]
Eu acredito que descobri porque isso está acontecendo. Parece que qualquer coisa com 8 elementos ou menos é instanciada como um PersistentArrayMap, que é exatamente o que eu quero, porque pelo que eu posso dizer, essa classe retém a ordem. No entanto, qualquer coisa com 9 ou mais elementos é instanciado como um PersistentHashMap, que não retém a ordem.
=>(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
Eu gostaria que minha macro pudesse ter mapas associativos de qualquer tamanho, então isso é um problema. Eu tentei tipo insinuando, ligação de desestruturação,para compreensão da lista e splicing unquote, tudo sem sucesso. Para desenhá-lo, nenhum dos itens a seguir funcionará:
(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))
Com este problema de brinquedo que apresento, percebo que poderia simplesmente escrever minha macro dessa forma e evitar o problema completamente:
=>(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]]
No entanto, para oreal problema que estou tentando resolver (o que não entendi), é importante (embora não seja 100% necessário) que a macro consiga obter mapas associativos. Parece que estou procurando como converter o argumento em um PersistentArrayMap antes que qualquer coisa tenha a chance de acontecer com ele. Pode haver algum outro caminho para uma solução que eu simplesmente não esteja considerando ou ciente.
Eu pesquisei o melhor que conheço e ainda não encontrei nada útil. Alguém tem algum pensamento / conselho?