2012-08-17 6 views
6

Biorąc pod uwagę następujący scenariusz:Jak zaktualizować zapisy w ref mapie w Clojure?

(defrecord Person [firstname lastname]) 
(def some-map (ref {})) 

(dosync 
    (alter some-map conj {1 (Person. "john" "doe")}) 
    (alter some-map conj {2 (Person. "jane" "jameson")})) 

Aby zmienić Book Nazwa z "joe" do "nick", mam następujące:

(dosync 
    (alter some-map (fn [m]     
        (assoc m 1 
         (assoc (m 1) :firstname "nick"))))) 

Jaki jest idiomatyczne to sposobem w Clojure?

Odpowiedz

5

Nie trzeba używać aktualizacji, w tym przypadku assoc-in jest dokładnie tym, czego potrzebujesz.

(dosync (alter some-map assoc-in [1 :firstname] "nick"))

+0

Uzgodnione, aktualizacja jest zbyt ogólna w tym przypadku. –

2

Edytuj: Na przykład assoc-in jest lepszy, ponieważ ignorujesz poprzednią wartość. Mając to odpowiedź dla przypadków, w których rzeczywiście potrzebują poprzednią wartość:

update-in ma zaktualizować zagnieżdżone struktury:

(alter some-map update-in [1 :firstname] (constantly "nick")) 

Ostatnim argumentem jest funkcja o wartości jaka ma być „zastąpiony” (jak assoc , nie zastępuje, ale zwraca nową strukturę.) W tym przypadku stara wartość jest ignorowana, stąd funkcja constantly, która zawsze zwraca "nick".

+0

można pominąć anonimowa funkcja otoki: '(alter-trochę aktualizacji map w [1: Imię] (stale "nick"))' –

+0

@JoostDiepenmaat Dzięki Ciągle zapominam o opcjonalny argumenty do funkcji wyższego rzędu w Clojure, będą edytowane. –

+0

Przyjąłem drugą odpowiedź, ale dziękuję za sugestię. Nie wiedziałem o tym nieustannie; teraz rozumiem, dlaczego moje inne próby zawiodły. – Odinodin