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 都有代码中的表示(作为向量和符号)。原子是具有身份的有状态对象,而 s 不是。

通常在编译时构造对象,然后尝试在运行时使用它(如 aot 编译可能完全分离这两种情况),将不会很有用。

您可以将原子的构造移动到产生的代码中(在 ` 内部),这样您就发出了在运行时进行构造的代码。不过,我并不确定这个宏的其他部分有何用途。

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