Clojure 宏抛出“CompilerException java.lang.IllegalStateException: Var clojure.core/unquote is unbound”当被叫时
我正在尝试编写一个 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
无论如何,这不应该是一个宏。函数非常强大,只有当映射和关键字都作为编译时文字给出时,宏版本才会起作用。
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.
`(~f ~@(map ~s ~symbols))
不起作用的原因是编译器因不必要的unquote
(~< /code>) 内的
unquote-splicing
(~@
)。unquote-splicing
取消引用外部syntax-quote
(`
),因此内部两个unquote
不会取消引用没有任何匹配的syntax-quote
,这就是您收到“未绑定”错误的原因。您想要做的是首先评估
(map ssymbols)
以获取操作数序列,然后将扁平化结果传递给函数 (~f
);因此正确的版本是:您可以轻松地验证这一点:
The reason that
`(~f ~@(map ~s ~symbols))
doesn't work is that the compiler chokes on the unnecessaryunquote
(~
) inside theunquote-splicing
(~@
). Theunquote-splicing
unquotes the outersyntax-quote
(`
), so the inner twounquote
s don't have any matchingsyntax-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:You can easily verify this with: