Clojure 宏抛出“CompilerException java.lang.IllegalStateException: Var clojure.core/unquote is unbound”当被叫时

发布于 2024-12-04 01:16:37 字数 570 浏览 1 评论 0原文

我正在尝试编写一个 clojure 宏,它允许我调用一个函数并使用提供的键值从映射/结构中检索参数,例如:

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

有人帮助吗我明白语法引用在这里是如何工作的吗?

I'm trying to write a clojure macro that lets me call a function and retrieve the arguments from a map/struct using the provided key values such as:

   (with-params  {:apple 2 :banana 3 :cherry 7} + :apple :banana)
   ;; 5

but when I try to use the macro that I wrote:

(defmacro with-params [s f & symbols]
  `(~f ~@(map ~s ~symbols)))

calling

   (with-params  {:apple 2 :banana 3 :cherry 7} + :apple :banana)

gives me

#<CompilerException java.lang.IllegalStateException: Var clojure.core/unquote is unbound. (NO_SOURCE_FILE:0)>

Could someone help me understand how syntax-quoting works here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

白龙吟 2024-12-11 01:16:37

无论如何,这不应该是一个宏。函数非常强大,只有当映射和关键字都作为编译时文字给出时,宏版本才会起作用。

(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

For what it's worth, this shouldn't be a macro anyway. A function is plenty powerful, and the macro version will only work if both the map and the keywords are given as compile-time literals.

(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
小红帽 2024-12-11 01:16:37

`(~f ~@(map ~s ~symbols)) 不起作用的原因是编译器因不必要的 unquote (~< /code>) 内的 unquote-splicing (~@)。 unquote-splicing 取消引用外部 syntax-quote (`),因此内部两个 unquote 不会取消引用没有任何匹配的 syntax-quote,这就是您收到“未绑定”错误的原因。

您想要做的是首先评估 (map ssymbols) 以获取操作数序列,然后将扁平化结果传递给函数 (~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

The reason that `(~f ~@(map ~s ~symbols)) doesn't work is that the compiler chokes on the unnecessary unquote (~) inside the unquote-splicing (~@). The unquote-splicing unquotes the outer syntax-quote (`), so the inner two unquotes don't have any matching syntax-quote, which is why you were getting the "unbound" error.

What you want to do is evaluate (map s symbols) first to get the sequence of operands, then pass the flattened result to the function (~f); therefore the correct version is:

(defmacro with-params [s f & symbols] `(~f ~@(map s symbols)))

You can easily verify this with:

(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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文