clojure - 在 clojure 中使用非命名空间符号

标签 clojure macros

这是一个最小的工作示例,展示了 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/

相关文章:

clojure - 何时评估集合的唯一元素?

variables - (部分 apply str)和 clojure 中的 apply-str ->

rest - 从 Spring Boot RestController 返回 Clojure PersistentVector

clojure - 在 clojure 原子交换中执行副作用的正确方法是什么

python - 将 Libre/Star/Openoffice Basic 宏转换为 python - 对象类型问题

machine-learning - 垃圾邮件分类器 Clojure

c - 将宏函数定义为(0)是什么意思?

java - 我们如何知道word文档中是否存在宏?

c - C中的MACRO执行步骤

c++ - 当 min 被定义为宏时如何调用 std::min()?