O'Reilly logo

Clojure Programming by Brian Carper, Christophe Grand, Chas Emerick

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

The Implicit Arguments: &env and &form

Earlier in Letting the User Pick Names, we mentioned that the defmacro macro itself is one of the rare anaphoric macros in Clojure. defmacro introduces two implicit local bindings: &env and &form.

&env

&env contains a map whose keys are the names[177] of all the current locals (the values of this map are unspecified). It may be useful for debugging purposes:

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

(let [x 1 y 2]
  (spy-env)
  (+ x y))
; {x 1, y 2}
;= 3

&env can also prove itself useful to safely optimize expressions at compile time. Here is a very crude version of such a macro that evaluates the provided expression at compile time if it does not use any locals defined within the context of the macro’s usage:

(defmacro simplify
  [expr]
  (let [locals (set (keys &env))]
    (if (some locals (flatten expr))     1
      expr                               2
      (do
        (println "Precomputing: " expr)
        (list `quote (eval expr))))))    3
1

Here we do a very crude search for references to the locals within the body of code provided to our macro.

If we suspect any such usage, then we return the code ...

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required