Search code examples
clojure

Why does map not change the atom in this code?


Why doesn't the atom change?

(defn table-rows [data]
  (def rows (atom [:tr]))
  (map #(swap! rows conj [:td {:name %}]) data)
  @rows)

(table-rows [{:name "foo"} {:name "bar"}])

evaluating table-rows as shown produces:

=> [:tr]

Why is this?


Solution

  • It doesn't change because map is lazy and the result is never used/realized.

    Apart from this the entire approach to this code snippet is wrong. Never declare a def inside another def/defn. Use let instead. If you want to transform every element in a sequence map is the correct function to use, but skip the atom. ->> can help to make things more readable too.

    (defn table-rows [data]
      (->> data
           (map (fn [{:keys [name] :as row}]
                  [:td {:name name}]))
           (into [:tr])))
    
    (table-rows [{:name "foo"} {:name "bar"}])
    

    As a general rule for local variable use let, never def.

    (defn table-rows [data]
      (let [rows (for [row data]
                   [:td (:name row)])]
        (into [:tr] rows)))