这是一个最小的工作示例,展示了 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]
我现在想定义一个类似的闭包来获取 undefined variable 的名称。
(defn take-names-fun []
(let [names (atom [])]
#((swap! names conj (simple-macro %)) (deref names))))
(def P (take-names-fun))
(P v1)
但这并没有像希望的那样工作;我收到错误:
Unable to resolve symbol: v1 in this context
有没有办法解决这个问题,以便我们可以将名称“v1”添加到上面定义的名称列表中?
我尝试使用宏来代替(受到“掌握 Clojure 宏”第 21 页上的语法技巧的启发)...但是 this answer 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))
事实上,我在这里遇到了另一个错误:
Can't embed object in code, maybe print-dup not defined:
但是,在 defn
中使用原子则没有这样的限制。也许最终我需要将我的符号放入命名空间中......?
最佳答案
不太确定您最终想要实现的目标是什么。
但是,由于 P
是一个函数,因此它将始终评估其参数。因此,如果您向其传递 undefined symbol ,您将收到错误消息。相反,您必须创建一个宏,以便可以引用 undefined symbol (以停止对参数求值),然后将其传递给 P
。这是一个执行此操作的示例。
user> (defn take-names-fun []
(let [names (atom [])]
(fn [arg] (swap! names conj (name arg)))))
#'user/take-names-fun
user> (def P (take-names-fun))
#'user/P
user> (defmacro PM [s] `(P (quote ~s)))
#'user/PM
user> (PM v1)
["v1"]
user> (PM v2)
["v1" "v2"]
user>
您可能会找到关于 Evaluation in Clojure 的文章有帮助。
关于clojure - 在 clojure 中使用非命名空间符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71861341/