带有函数定义的宏,包括 set!不在 Clojurescript 中工作

Macro with a function definition including set! not working in Clojurescript

我正在尝试定义一个应该执行以下操作的宏:

我在 clojure 文件中定义了以下内容:

(defmacro defprop
  [prop-name init-value]
  `(do
    (def ~prop-name ~init-value)
    (def ~(symbol (str prop-name "-other")) ~init-value)
    (defn ~(symbol (str prop-name "-11")) [] (set! ~prop-name 11))
    (defn ~(symbol (str prop-name "-set")) [new-val] (set! ~prop-name new-val))))

像这样从 clojurescript 调用时(cmacros 是名称空间别名):

(cmacros/defprop production 350)

我得到 'production' 和 'production-other' 的定义,函数 'production-11' 有效(并将生产值设置为 11),但最后一个无效。 我在不同的浏览器中收到不同的错误。 Chrome 说 "Uncaught SyntaxError: Unexpected token ."。火狐 "SyntaxError: missing ) after formal parameters".

Firefox 指出的违规 javascript 代码如下所示:

cgamemini.core.production_set = (function
  cgamemini$core$production_set(cgamemini.macros.new_val) {
    return cgamemini.core.production = cgamemini.macros.new_val;
  }
);

虽然我不是 js 专家,但似乎所有括号都正确。 出了什么问题?为什么 -11 定义有效但 -set 无效?

问题是new-val。 Clojure 宏扩展不理解语法,因此它不知道 new-val 应该是一个参数——宏扩展中出现的任何裸符号自动命名为当前命名空间。这就是您在输出中看到 cgamemini$core$production_set(cgamemini.macros.new_val) 的原因。你想要做的是使用卫生宏语法来指示应该创建一个没有命名空间的新符号,例如

`(defn ~(symbol (str prop-name "-set")) [new-val#] (set! ~prop-name new-val#))

另一种方法是注入您的符号:

`(defn ~(symbol (str prop-name "-set")) [~'new-val] (set! ~prop-name ~'new-val))