What I figured I can have a look at is which macros are being expanded, and marking some of them as safe from fiddling with ns’s. I’d imagine that let/and/or, and a bunch of other core macros should fall into this category.
This shows promise:
(def ns-safe-symbol #{#'clojure.core/fn
#'clojure.core/defn
#'clojure.core/defn-
#'clojure.core/let
#'clojure.core/delay
#'clojure.core/when
#'clojure.core/when-let
#'clojure.core/or
#'clojure.core/and
#'clojure.core/->>
})
(defn macroexpand-1
"If form represents a macro form or an inlineable function,returns its expansion,
else returns form."
([form] (macroexpand-1 form (empty-env)))
([form env]
(env/ensure (global-env)
(cond
(seq? form)
(let [[op & args] form]
(if (specials op)
form
(let [v (resolve-sym op env)
m (meta v)
local? (-> env :locals (get op))
macro? (and (not local?) (:macro m)) ;; locals shadow macros
inline-arities-f (:inline-arities m)
inline? (and (not local?)
(or (not inline-arities-f)
(inline-arities-f (count args)))
(:inline m))
t (:tag m)]
(cond
macro?
(let [res (apply v form (:locals env) (rest form))] ; (m &form &env & args)
(when-not (ns-safe-symbol v)
#_ (println "symbol" v)
(update-ns-map!))
(if (obj? res)
(vary-meta res merge (meta form))
res))
inline?
(let [res (apply inline? args)]
(update-ns-map!)
(if (obj? res)
(vary-meta res merge
(and t {:tag t})
(meta form))
res))
:else
(desugar-host-expr form env)))))
(symbol? form)
(desugar-symbol form env)
:else
form))))
That’s from analyzer/jvm.clj
This is the count of macros in our project:
So given that let
doesn’t alter the namespace (which I don’t think it does), I could save 20586 calls to build-ns-map