Search code examples
clojurering

Why merge-with is used instead of simple 'merge' in Ring, Clojure?


I'm very new to Clojure and learning Clojure by reading good open source code. So I choose Ring and starting to read the code but got stuck in assoc-query-params function. (which is located in ring.middleware/params.clj)

And I could not understand why "merge-with" is used. Can anybody help me to understand this code snippet?

(defn- assoc-query-params
  "Parse and assoc parameters from the query string with the request."
  [request encoding]

  ; I think (merge request (some-form)) is enough
  ; but the author used merge-with with merge function.

  (merge-with merge request
    (if-let [query-string (:query-string request)]
      (let [params (parse-params query-string encoding)]
        {:query-params params, :params params})
      {:query-params {}, :params {}})))

Solution

  • Here's the description of the merge function: reworded it says that if a key is met more than once than value in the latest map will be selected. In the example that you posted that would mean that values of :query-params :params will be taken as is from the tail of the function instead of combining them with what's in the request.

    Let's look at the example:

    (def m {:a {:a-key1 "value1"} :b {:b-key1 "value3"} :c {}})
    (def m2 {:a {:a-key2 "value2"} :b {}})
    
    (merge m m2)
    ;-> {:a {:a-key2 "value2"}, :b {}, :c {}}
    
    (merge-with merge m m2)
    ;-> {:a {:a-key1 "value1", :a-key2 "value2"}, :b {:b-key1 "value3"} :c {}}
    

    So (merge-with merge ...) construct gives us a way to merge maps in the map. You can look at it this way: merge-with will group all key/value pairs by the key (:a :b :c in our example) and apply merge to their values.

    {:a (merge {:a-key1 "value1"} {:a-key2 "value2"}) 
     :b (merge {:b-key1 "value3"} {})
     :c (merge {})}
    

    Having handled that I think that the original intention of the assoc-query-params author is to extend :query-params and :params instead of completely replacing them.