为什么在这个Clojure宏上执行macroexpand-1时会出现NullPointerException?

时间:2012-05-15 16:18:01

标签: macros clojure

我正在学习Clojure宏,当我尝试在这个宏上使用macroexpand-1时,我得到一个NullPointerException:

(def config {:ns 'bulbs.neo4jserver.client, 
             :root-uri "http://localhost:7474/db/data/"})
(def data {:name "James"})

(defmacro create
  [config data]
  `(~(ns-resolve (:ns config) 'create-vertex) config data))

(macroexpand-1 '(create config data))

尝试编译它会返回:

 Unknown location:
   error: java.lang.NullPointerException

 Compilation failed.

但评估宏的身体......

`(~(ns-resolve (:ns config) 'create-vertex) config data)

...返回此...

(#'bulbs.neo4jserver.client/create-vertex bulbs.vertices/config bulbs.vertices/data)

......这就是我想要的。

更新:如果我用(:ns config)手动替换'bulbs.neo4jserver.client,那么错误就会消失 - 你如何让(:ns config)玩得很好?

2 个答案:

答案 0 :(得分:3)

您正在尝试混合使用宏扩展时和运行时信息。本地“config”不包含#'config var的内容,而是包含'config。

符号

如果查看完整堆栈跟踪,而不仅仅是错误消息,您将看到ns-resolve正在传递为nil:

user=> (pst)
NullPointerException 
        java.util.concurrent.ConcurrentHashMap.get (ConcurrentHashMap.java:796)
        clojure.lang.Namespace.find (Namespace.java:188)
        clojure.core/find-ns (core.clj:3657)
        clojure.core/the-ns (core.clj:3689)
        clojure.core/ns-resolve (core.clj:3879)
        clojure.core/ns-resolve (core.clj:3876)
        clj.core/create (NO_SOURCE_FILE:7)

了解以下内容后,您将了解原始问题:

user=> (def bar [1 2 3])
user=> (defmacro foo [x] [(class x) (pr-str x)])
user=> (foo (get bar 2))
[clojure.lang.PersistentList "(get bar 2)"]

答案 1 :(得分:1)

为什么这首先是一个宏?在这种情况下,这似乎是正常的功能。

请记住,config与您输入的文字值绑定,因此如果您执行

(def c {:ns 'foo})  
(create c 1)

config将只是'c,而不是c在运行时引用的地图。