Search code examples
clojure

Clojure: anonymous function with reduce


I am new to clojure and have noticed this example at clojure docs.

(reduce (fn [m [k v]] (assoc m v k)) {}{:b 2 :a 1 :c 3})

Output: ;;=> {2 :b, 1 :a, 3 :c}

Can anybody explain behind logic of the code?


Solution

  • reduce applies a function to an accumulator and each element in a sequence, building a final result. ClojureDocs gives the signature for reduce as either (reduce f coll) or (reduce f val coll). Your example has the latter signature with elements matching as follows:

    • f : The function to apply to each entry, (fn [m [k v]] ...
    • val : The initial accumulator, {}
    • coll : The collection to operate on, {:b 2 :a 1 :c 3}

    Note that there is no delimiter (i.e., space) between the second and the third parameter of your reduce call. Clojure does not require one.

    Then, looking at the inner anonymous function: (fn [m [k v]] (assoc m v k)). The first argument m is the current value of accumulator, which was {} at the start of the reduce. Destructuring syntax is used for the second argument, which is the current value to be prosessed, that is, a map entry. The map entry is destructured to its key k and value v. The body of the anonymous function simply puts a new "reversed" entry to the accumulator (i.e., map), so that the value of the original sequence v is the key, and the key k becomes the value. The result is similar to applying the Clojure API function map-invert.

    Note that there is a separate reduce-kv function for reducing associative collections (e.g., a map). reduce-kv "does the destructuring for you". This allows the anonymous function to be written as:

    (fn [m k v] (assoc m v k))
    

    Or even more simply with the short notation:

    #(assoc %1 %3 %2)