Стандартные карты и наборы Clojure являются неизменными (и постоянными) [1], поэтому они работают так же хорошо в параллельных программах. Вы можете сохранить их в ref / agent / var / atom в зависимости от ваших требований, и вы можете просто обновить ref / agent / var / atom, как всегда.
Вы можете иметь более изменчивую карту, если значения на самом деле являются ссылками, например:
{:a (ref #{1 2 3})
:b (ref #{4 5 6})}
В этом случае вы сможете фактически добавить значения к уже существующему ключу (конечно, в транзакции). Добавление и удаление ключей будет по-прежнему возвращать новые карты, которые будут иметь те же ссылки, что и исходные карты, и поэтому изменения одной из них будут видны другим:
user=> (def mmap {:a (ref #{1 2 3}) :b (ref #{4 5 6})})
#'user/mmap
user=> mmap
{:a #<Ref@be0446: #{1 2 3}>, :b #<Ref@10aa282: #{4 5 6}>}
user=> (def mmap2 (assoc mmap :c (ref #{7 8 9})))
#'user/mmap2
user=> mmap2
{:c #<Ref@405f6: #{7 8 9}>, :a #<Ref@be0446: #{1 2 3}>, :b #<Ref@10aa282: #{4 5 6}>}
user=> mmap
{:a #<Ref@be0446: #{1 2 3}>, :b #<Ref@10aa282: #{4 5 6}>}
user=> (dosync (alter (:a mmap2) conj 0))
#{0 1 2 3}
user=> mmap
{:a #<Ref@be0446: #{0 1 2 3}>, :b #<Ref@10aa282: #{4 5 6}>}
user=> mmap2
{:c #<Ref@405f6: #{7 8 9}>, :a #<Ref@be0446: #{0 1 2 3}>, :b #<Ref@10aa282: #{4 5 6}>}
[1] То есть добавление / удаление / изменение ключей и значений фактически возвращает новую карту без изменения оригинала.