[英]Clojure macro throws “CompilerException java.lang.IllegalStateException: Var clojure.core/unquote is unbound” when called
我正在嘗試編寫一個clojure宏,它允許我調用一個函數並使用提供的鍵值從map / struct中檢索參數,例如:
(with-params {:apple 2 :banana 3 :cherry 7} + :apple :banana)
;; 5
但是當我嘗試使用我寫的宏時:
(defmacro with-params [s f & symbols]
`(~f ~@(map ~s ~symbols)))
調用
(with-params {:apple 2 :banana 3 :cherry 7} + :apple :banana)
給我
#<CompilerException java.lang.IllegalStateException: Var clojure.core/unquote is unbound. (NO_SOURCE_FILE:0)>
有人可以幫助我理解語法引用如何在這里工作嗎?
對於它的價值,無論如何這不應該是一個宏。 函數非常強大,只有當map和關鍵字都以編譯時文字形式給出時,宏版本才有效。
(defmacro with-params-macro [s f & symbols]
`(~f ~@(map s symbols)))
(defn with-params-fn [s f & symbols]
(apply f (map s symbols)))
user> (with-params-macro {:x 1} (fn [z] z) :x)
1
user> (let [params {:x 1}]
(with-params-macro params (fn [z] z) :x))
nil
user> (let [params {:x 1}]
(with-params-fn params (fn [z] z) :x))
1
`(~f ~@(map ~s ~symbols))
不起作用的原因是編譯器在unquote-splicing
( ~@
)內部對不必要的unquote
( ~
)進行choke。 unquote-splicing
取消syntax-quote
外部syntax-quote
( `
),因此內部兩個unquote
s沒有任何匹配的syntax-quote
,這就是你得到“未綁定”錯誤的原因。
你想要做的是首先評估(map s symbols)
以得到操作數序列,然后將展平結果傳遞給函數( ~f
); 因此正確的版本是:
(defmacro with-params [s f & symbols] `(~f ~@(map s symbols)))
您可以使用以下方法輕松驗證:
(macroexpand '(with-params {:a 1 :b 2 :c 5} * :a :b :c)) ;; (* 1 2 5)
(with-params {:a 1 :b 2 :c 5} * :a :b :c) ;; 10
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.