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

被选中
 
最佳答案

宏是接受代码并返回代码的函数。原子是具有状态的对象 - 在代码中无法用唯一标识符表示它们,因此这行不通。

您实际上想做什么?

by
编辑 by
>宏是接受代码并返回代码的函数。原子是有状态的对象 - 无法用代码表示它们具有身份,因此这不会起作用。

我不确定我明白这个意思。

>你实际上想做什么?

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

nbsp; (defmacro x []
nbsp;   (let [a (atom {})
nbsp;        s (gensym)]
      `(fn []
         (let [~s ~a]
           ))))
by
上面的例子与什么不同?

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

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

通常,在编译时构建对象然后尝试在运行时使用它(如 aot 编译可能完全分开这些)通常是没有用的。

您可以将原子的构建移动到生成的代码(即内的 ` )中,这样您就可以生成在运行时构建的代码。但这并不是说这个宏的其他部分有什么实际用途。

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