Question

I am working on updating counters in a map ref in Clojure.

(defn increment-key [this key]
    (dosync
        (let [value (get @this key)]
            (if (= value nil)
                (alter this assoc key (ref 1))
                (alter this assoc key (alter value inc))))))

However, it looks like the alter value inc statement is losing the reference:

(defn -main [& args]
    (def my-map (ref {}))
    (increment-key my-map "yellow")
    (println my-map)
    (increment-key my-map "yellow")
    (println my-map))

Which prints:

$ lein run
#<Ref@65dcc2a3: {yellow #<Ref@3e0d1329: 1>}>  
#<Ref@65dcc2a3: {yellow 2}>

How can I keep the same reference while updating it in this scenario?

Was it helpful?

Solution

You were almost there. Below is the solution, check the last line of increment-key, you just need to alter the value (not alter the key in the map as you were doing, coz that was causing the key to be updated with the alter return value which in you example was 2, remember alter returns the new value of the ref, not the ref itself). Also don't use def inside a def, you should use let (in your -main function)

(defn increment-key [this key]
    (dosync
        (let [value (get @this key)]
            (if (= value nil)
                (alter this assoc key (ref 1))
                (alter value inc)))))

(defn -main [& args]
  (let [my-map (ref {})]
       (increment-key my-map "yellow")
       (println my-map)
       (increment-key my-map "yellow")
       (println my-map)))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top