在Clojure中使用非命中板的符号
这是一个最小的工作示例,展示了 Clojure 如何处理非命名空间符号:
(defmacro simple-macro [s]
(name `~s))
(str "And the answer is "
(simple-macro v1))
现在我想做一些更复杂的事情。受到这个例子的启发:
(defn typical-closure []
(let [names (atom [])]
(fn [arg] (swap! names conj arg) @names)))
(def Q (typical-closure))
(Q 1)
(Q 2)
;; [1 2]
我现在想定义一个类似的闭包来获取未定义变量的名称。
(defn take-names-fun []
(let [names (atom [])]
#((swap! names conj (simple-macro %)) (deref names))))
(def P (take-names-fun))
(P v1)
但这并没有达到预期效果;我收到错误:
在此上下文中无法解析符号:v1
解决此问题,以便我们可以将名称“v1”添加到上面定义的名称列表中?
我尝试使用宏(受到“掌握 Clojure 宏”第 21 页上的语法技巧的启发)...但是 ask.clojure.org 上的这个答案 表示在宏中的原子上定义闭包是没有意义的。
(defmacro take-names-macro []
(let [names (atom [])]
`(fn [~'x] (swap! ~names conj (simple-macro ~'x)) (deref ~names))))
(def R (take-names-macro))
事实上,我在这里遇到另一个错误:
无法在代码中嵌入对象,可能 print-dup 未定义:
但是,在 defn
中使用原子没有这样的限制。也许最终我需要将符号放入命名空间中......?
Here's a working minimal example showing how Clojure can handle non-namespaced symbols:
(defmacro simple-macro [s]
(name `~s))
(str "And the answer is "
(simple-macro v1))
Now I'd like to do something more complicated. Inspired by this example:
(defn typical-closure []
(let [names (atom [])]
(fn [arg] (swap! names conj arg) @names)))
(def Q (typical-closure))
(Q 1)
(Q 2)
;; [1 2]
I now want to define a similar closure to take the names of undefined variables.
(defn take-names-fun []
(let [names (atom [])]
#((swap! names conj (simple-macro %)) (deref names))))
(def P (take-names-fun))
(P v1)
But this doesn't work as hoped; I get the error:
Unable to resolve symbol: v1 in this context
Is there a way to fix this so that we can add the name "v1" to the list of names defined above?
I tried using a macro instead (inspired by a syntax trick on page 21 of "Mastering Clojure Macros")... but this answer on ask.clojure.org says it doesn't make sense to define a closure over an atom in a macro.
(defmacro take-names-macro []
(let [names (atom [])]
`(fn [~'x] (swap! ~names conj (simple-macro ~'x)) (deref ~names))))
(def R (take-names-macro))
And indeed, I get another error here:
Can't embed object in code, maybe print-dup not defined:
However, there is no such restriction for using atoms inside defn
. Maybe at the end of the day I need to put my symbols in a namespace...?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不太确定您最终试图完成的是什么。
但是,由于
p
是一个函数,因此它将始终评估其参数。因此,如果将其传递给未定义的符号,您将获得错误的错误。相反,您必须创建一个宏,以便可以引用未定义的符号(以停止对参数的评估),然后将其传递给p
。这是这样做的示例。您可能会在
Not quite sure what it is that you're ultimately trying to accomplish.
But, since
P
is a function, it will always evaluate its arguments. So, if you pass it an undefined symbol, you'll get the error you got. Instead, you have to create a macro so that you can quote the undefined symbol (to stop the evaluation of the argument) and then pass that toP
. Here is an example that does that.You might find the article on Evaluation in Clojure helpful.
@Dorab的答案很好。
但是您也可以告诉自己:“将未定义的变量输入函数时,我必须引用它们以避免对它们进行评估!”
因此,之后:
做:
这样您就不需要宏,可以在评估和未评估的参数(未定义的符号)之间交替。
@dorab's answer is nice.
But you could also tell yourself: "When entering undefined variables into a function, I have to quote them to avoid evaluation of them!"
So, after:
Do:
In this way you don't need the macro and you can alternate between evaluated and not-evaluated arguments (undefined symbols).
因此,不幸的是,按照
fn
在 clojure 中编写的方式,无法从fn
主体中获取作为参数传递的 var 的名称。凭借对 clojure src 的更多经验,也许能够更好地解释为什么会这样,我最初的猜测是它与保持线程本地作用域的隔离和惰性有关。但是绝对没有什么可以阻止您使用闭包想法编写一个包装其他宏的宏!
下面是如何编写类似内容的示例:
https://stackoverflow.com/a/11857444
So with the way
fn
's are written in clojure there is unfortunately no way to get the name of the var being passed as a param from within thefn
body.. Someone with more experience with the clojure src may be able to explain better why that is, my initial guess would be that it has something to do with keeping thread local scopes isolated and lazy.But there's absolutely nothing stopping you from writing a macro that wraps other macros using your closure idea!
Here's an example of how something like that may be written:
https://stackoverflow.com/a/11857444