(defn do-to-map [amap keyseq f]
(reduce #(assoc %1 %2 (f (%1 %2))) amap keyseq))
Podział:
Pomaga to patrzeć inside-out. W Clojure mapy hash działają jak funkcje; jeśli wywołasz je jako funkcję z kluczem jako argumentem, zwracana jest wartość skojarzona z tym kluczem. Tak więc biorąc pod uwagę jednego klawisza, aktualna wartość dla tego klucza można uzyskać poprzez:
(some-map some-key)
Chcemy wziąć stare wartości i zmieniać je do nowych wartości poprzez wywołanie niektórych funkcji f
na nich. Tak więc biorąc pod uwagę jednego klawisza, nowa wartość będzie:
(f (some-map some-key))
Chcemy powiązać tę nową wartość z tego klucza w naszym hash-map „zastępując” starą wartość. To, co robi assoc
:
(assoc some-map some-key (f (some-map some-key)))
(„Replace” jest w cudzysłowie, ponieważ zastraszania-nie jesteśmy mutacji pojedynczego obiektu hash-map; wracamy nowy, niezmienny, zmieniany hash-mapy obiektów za każdym razem nazywamy assoc
. to jest nadal szybki i skuteczny w Clojure ponieważ hash-mapy są trwałe i struktura akcji podczas assoc
im.)
Musimy wielokrotnie assoc
nowe wartości na naszej mapie, jeden klawisz naraz. Więc potrzebujemy jakiegoś rodzaju konstrukcji pętlowej. Chcemy zacząć od naszej oryginalnej mapy skrótów i pojedynczego klucza, a następnie "zaktualizować" wartość tego klucza. Następnie przechodzimy do tej nowej tablicy skrótów i następnego klucza, i "aktualizujemy" wartość tego następnego klucza. Powtarzamy to dla każdego klucza, po jednym na raz, i ostatecznie zwracamy mapę hash, którą "zgromadziliśmy". Tak właśnie robi reduce
.
- Pierwszym argumentem
reduce
to funkcja, która przyjmuje dwa argumenty: wartość „akumulator”, która jest wartością trzymamy „odnowienia” kółko; i pojedynczy argument użyty w jednej iteracji do zrobienia części akumulacji.
- Drugi argument do
reduce
jest wartością początkową przekazaną jako pierwszy argument do tego fn
.
- Trzeci argument do
reduce
jest zbiorem argumentów, które należy przekazać jako drugi argument do tego fn
, po jednym na raz.
Więc:
(reduce fn-to-update-values-in-our-map
initial-value-of-our-map
collection-of-keys)
fn-to-update-values-in-our-map
jest tylko oświadczenie assoc
z góry, owinięte w anonimowej funkcji:
(fn [map-so-far some-key] (assoc map-so-far some-key (f (map-so-far some-key))))
więc podłączając go do reduce
:
(reduce (fn [map-so-far some-key] (assoc map-so-far some-key (f (map-so-far some-key))))
amap
keyseq)
W Clojure, istnieje skrót do pisania anonimowych funkcji: #(...)
to anonimowy fn
składający się z pojedynczej formy, w której %1
jest związany z pierwszym argumentem funkcji anonimowej, %2
z drugim, itd. Więc nasz fn
z góry może być zapisany równoważnie jako:
#(assoc %1 %2 (f (%1 %2)))
To daje nam:
(reduce #(assoc %1 %2 (f (%1 %2))) amap keyseq)
Czy mógłbyś przekazać oświadczenie z opisem oświadczenia dla nas nowego w Clojure? –
Nadzieję, że pomaga. –
Ta notacja # (...) jest niesamowita. Świetna odpowiedź! –