3

我总是喜欢有一种自动解析符号的方法。例如,如果我在“用户”命名空间中并且没有在“clojure.string”命名空间中“使用”符号,而不是:

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

我想这样写:

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

我简单地实现了一个“调用”宏,如下所示:

(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))))))

以下测试总是可以的:

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

当我将宏作为“doc”的参数传递时,就会出现问题:

(call doc clojure.repl/doc)

然后,有一个例外:

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

所以这就是为什么?谢谢

4

1 回答 1

2

您可以在编译时在宏中解析符号,如下所示:

(defmacro call [sym & args]
  (let [f (first (distinct (remove nil? (map #(ns-resolve % sym) (all-ns)))))]
      `(~f ~@args)))
于 2012-12-27T07:47:19.657 回答