Can you elaborate?
《Clojure Programming》chapter 5
(def defmacro (fn [&form &env name & args]))
Yes, but notice this line:
(. (var defmacro) (setMacro))
Which will notify the compiler to treat
defmacro as a Macro, and therefore it will be macro-expanded at compile-time (with no runtime penalty).
There are many surprising uses to macros. One of them is splitting code. Imagine
(let [that (we-have) several (elements) of (computation) layed-out (as such) in (a let)] ...)
Let’s suppose we also want to perform a series of operations tangentially to the sequence of computations above, for instance to do some logging. We might end up with something like this.
(let [that (we-have) _ (log that) several (elements) _ (log several) of (computation) _ (log of) layed-out (as such) _ (log layed-out) in (a let) _ (log in)] ...)
To preserve readability by separating orthogonal sides of code we can manage something like this.
(defmacro with-logging [[_let bindings] `(let ~(add-logging bindings))) (with-logging (let [that (we-have) several (elements) of (computation) layed-out (as such) in (a let)] ...)))
What’s nice is that instead of refactoring the initial let into a new abstraction like functions that compose monadically, I can stick to my code and let the refactoring be done by a macro in terms common to all these competing abstractions: in Clojure like in all lisps, inert code is just nested lists of symbols.
Also they can be very short and powerful. I wrote this one out of frustration fighting multiple levels of
ifs to cohabit with a few
lets and decided to flatten it all.
;; Goal: a macro similar to `let` that evaluates its bindings lazily. (require '[clojure.tools.macro :refer [symbol-macrolet]]) (defmacro lay [[sym expr & more-bindings] & body] (let [delay-sym (gensym (str "laid-" sym "-"))] `(let [~delay-sym (delay ~expr)] (symbol-macrolet [~sym (deref ~delay-sym)] [email protected](if (empty? more-bindings) body `[(lay ~more-bindings [email protected])]))))) ;; Simple example (defmacro lay-it [& body] `(lay [~'a (print "a") ~'b (print "b") ~'c (do ~'b (print "c"))] [email protected] (newline))) (lay-it a) ;; a (lay-it b) ;; b (lay-it a b) ;; ab (lay-it b a) ;; ba (lay-it c) ;; bc (lay-it c a) ;; bca (lay-it c b a) ;; bca (no re-evaluation, uses cached result instead)