Search code examples
clojuremacros

Is there a second undocumented evaluation phase for the &env macro?


This macro returns the values of the "magic" &env as a map, so that (let [xyz "ZYX"] (get-env)) returns {xyz "ZYX"}, where the key is a Symbol.

(defmacro get-env []
   (let [ks (keys &env)]
     `(zipmap '~ks [~@ks])))

The expression '~ks evaluates the ks into Symbols at the macro-expansion phase (right?), but then quotes the expansion, so that the Symbols don't get evaluated into their values ("ZYX" in our example), but rather stay as Symbols (xyz). Is that right?

About [~@ks]: It evaluates ks into an seq of Symbols at the macro-expansion phase (right?) (and splices them and forms a vector with []). But how does that allow these Symbols to get further evaluated into their values ("ZYX" in our example) -- is there a second evaluation step, applied immediately after the first?

Another variant is

(defmacro local-env [] (->> (keys &env)
  (map (fn [k] [(list 'quote k) k])) (into {})))

Solution

  • Your macro takes all the keys from the env. Then it uses the keys (a list of symbols) to zip both the list of keys with spliced symbols inside a vector. So what you get from

    (let [x 42]
      (get-env))
    

    is

    (let [x 42]
      (zipmap '(x) [x]))
    

    This is a compile-time transformation of your code (the whole point of macros). The resulting code at runtime will use the 42 from the bound x.