Standardowe mapy i zestawy Clojure są niezmienne (i trwałe) [1], więc działają równie dobrze w programach współbieżnych. Możesz chcieć przechowywać je w ref/agent/var/atom w zależności od twoich wymagań i możesz po prostu zaktualizować ref/agent/var/atom jak nigdy wcześniej.
Można mieć bardziej zmienny mapę, jeśli wartości są rzeczywiście sędziowie, podobnie jak to:
{:a (ref #{1 2 3})
:b (ref #{4 5 6})}
W tym przypadku, będziesz w stanie rzeczywiście dodać do już istniejących wartości klucza (w transakcji kierunek). Dodawanie i usuwanie kluczy jeszcze powróci nowe mapy, które mają te same pozycje literatury jako oryginalnych map, a więc zmiany w jednym z nich będzie widoczny dla innych:
user=> (def mmap {:a (ref #{1 2 3}) :b (ref #{4 5 6})})
#'user/mmap
user=> mmap
{:a #<[email protected]: #{1 2 3}>, :b #<[email protected]: #{4 5 6}>}
user=> (def mmap2 (assoc mmap :c (ref #{7 8 9})))
#'user/mmap2
user=> mmap2
{:C#<[email protected]: #{7 8 9}>, :a #<[email protected]: #{1 2 3}>, :b #<[email protected]: #{4 5 6}>}
user=> mmap
{:a #<[email protected]: #{1 2 3}>, :b #<[email protected]: #{4 5 6}>}
user=> (dosync (alter (:a mmap2) conj 0))
#{0 1 2 3}
user=> mmap
{:a #<[email protected]: #{0 1 2 3}>, :b #<[email protected]: #{4 5 6}>}
user=> mmap2
{:C#<[email protected]: #{7 8 9}>, :a #<[email protected]: #{0 1 2 3}>, :b #<[email protected]: #{4 5 6}>}
[1] Oznacza to, że dodawanie/usuwanie/modyfikowanie kluczy, a wartości faktycznie zwracają nową mapę, bez zmiany oryginału.
Jest to błędne przekonanie, że Haskell nie pozwala mutacji. To robi. Połów jest taki, że wszystkie mutacje muszą być należycie odnotowane w typach; dlatego typowy sposób łączenia operacji mutacji polega na interfejsie monady. Haskellerowie mogą "cofnąć się" do zmienności w taki sam sposób, jak Scala i Clojure, z wyjątkiem Haskella, którego nie można oszukiwać i sprawiać, że funkcja jest czysta, gdy nie jest. Jeśli jednak możesz w pełni enkapsulować mutację w swojej funkcji, to nadal możesz odsłonić czysty interfejs. –