2024 Clojure 状态调查 中分享您的想法!

欢迎!请参阅 关于 页面以了解更多此功能的信息。

+1

我试图在宏函数中创建一个原子,并在宏输出形式中嵌入对该原子的引用。

(defmacro x []
  (let [a (atom {})]
    `(fn []
       ~a)))

尝试使用此宏会产生这个错误。

`

(x)
Syntax error compiling fn* at (/tmp/form-init15982565344292085756.clj:1:1).
Can't embed object in code, maybe print-dup not defined: clojure.lang.Atom@350e9f50

`

我尝试定义一个空的 print-dup 重载,但它导致了不同的错误。

`

(defmethod print-dup clojure.lang.Atom [x w])
(x)
Syntax error compiling fn* at (/tmp/form-init15982565344292085756.clj:1:1).
Can't embed unreadable object in code: clojure.lang.Atom@5f3623b3

`

我本来以为这应该可以工作,因为 Clojure 有 eval。这里有什么问题呢?

1 答案

+2

被选中
 
最佳答案

宏是接受代码并返回代码的函数。原子是具有状态的对象——在代码中不能用标识符表示它们,因此这不会奏效。

你实际上想做什么?


编辑
>宏是接受代码并返回代码的函数。原子是状态对象——无法用代码中的身份来表示它们,所以这不会奏效。

我不太确定我是否理解了这句话的意思。

>你实际上想要做什么?

该宏将返回一个函数,当它被评估时将修改原子值,然后一些其他代码将读取这些值。这是一个更好的例子

  (defmacro x []
    (let [a (atom {})
       s (gensym)]
    `(fn []
        (let [~s ~a]
         ))))
上面的例子与以下有何不同?

(defmacro x []
  (let [a (vec (range 3))
       s (gensym)]
    `(fn []
       (let [~s ~a]
        ))))

这行代码是可行的。
在你的第二个例子中,a 和 s 都是作为代码的表示(作为一个向量和符号)。原子是一个有身份和状态的对象,不是。

通常,在编译时构建对象并在运行时使用它(如aot编译可能完全分离这些)将没有太多用处。

可以将原子的构建移动到发出的代码中(在 " here" 内部),这样你就可以发出在运行时构建的代码。不过我不确定这个宏的其余部分有什么作用。

你实际上想做什么?
...