xiepan
xiepan

Reputation: 783

How to write a macro resolve the symbol automatically

I'm always fancy that there is a method to resolve symbols automatically. For example, if I am in the "user" namespace and have not "used" symbols in the `clojure.string' namespace, instead of:

(clojure.string/split "a-b-c" #"-")

I want to write as this:

(call split "a-b-c" #"-")

I have simply implemented a `call' macro as this:

(defmacro call [sym & args]
  `(let [fn# (first (distinct (remove nil? (map #(ns-resolve % '~sym) (all-ns)))))]
     (if-not ((meta fn#) :macro) 
       (fn# ~@args)
       (eval (list fn# ~@(map #(list 'quote %) args))))))

the following tests are always ok:

(call list 'a 'b)
(call apropos "list")
(call doc list)
(call doc clojure.string/split)

the problem happens when I pass a macro as the argument of `doc':

(call doc clojure.repl/doc)

then, there is a exception:

CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.repl/doc, compiling:(NO_SOURCE_PATH:112)

So, that's why? thanks

Upvotes: 3

Views: 678

Answers (1)

Ankur
Ankur

Reputation: 33637

You can resolve the symbol at compile time in the macro like this:

(defmacro call [sym & args]
  (let [f (first (distinct (remove nil? (map #(ns-resolve % sym) (all-ns)))))]
      `(~f ~@args)))

Upvotes: 2

Related Questions