Макрос Clojure, который сохранит ассоциативный порядок отображения

В качестве предисловия я нахожусь на Windows 7 (64-разрядная версия), работает под управлением Java версии 6 (обновление 33), используяclooj как моя IDE. Я не пытался воспроизвести мою проблему в любой другой системе. У меня есть опыт работы с 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

Я хотел бы, чтобы мой макрос мог брать ассоциативные карты любого размера, так что это проблема. Я пробовал намеки типа, деструктурирование привязки,for понимание списка и соединение без кавычек, все без успеха. Чтобы сделать это, ни одно из следующего не будет работать:

(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]]

Однако дляactual Проблема, которую я пытаюсь решить (в которую я не попал), важно (хотя и не обязательно на 100%), чтобы макрос мог принимать ассоциативные карты. Похоже, я ищу, как преобразовать аргумент в PersistentArrayMap до того, как что-нибудь с ним случится. Там может быть какой-то другой путь к решению, которое я просто не рассматриваю или не знаю.

Я исследовал лучшее, что мне известно, и пока не нашел ничего полезного. У кого-нибудь есть какие-нибудь мысли / советы?

Ответы на вопрос(2)

Ваш ответ на вопрос