Search code examples
clojure

How to create a map from a group of bindings using their names as keys?


I want something like an inverse of {:keys [...]} construct:

(let [x 1 y 2 z 3] (create-map x y z))

...should return {:x 1 :y 2 :z 3}.

In other words, I want to avoid typing name of each variable twice as in {:x x :y y :z z}.

An example of what I want this function for:

(defn create-some-service-handle [user-id password api-key] 
    { :api-key api-key 
      :user-id user-id 
      :connection (obtain-connection user-id password) })

Solution

  • If you are looking for something that will be able to stand right in exactly where create-map is, then you will need a macro, because you will need to take those symbols unevaluated. It would be a pretty straightforward macro:

    (defmacro create-map
      [& syms]
      (zipmap (map keyword syms) syms))
    

    This simply takes the unevaluated symbols, maps keyword down them to obtain a sequence of keywords, then zipmaps the key sequence with the original symbols. Since it is a macro, after this the resulting form will be evaluated, yielding a mapping of keywords to values (the values the symbols refer to).

    So that if you go to do:

    (let [x 1 y 2 z 3] (create-map x y z))
    

    ...it will return:

    {:x 1 :y 2 :z 3}