0

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

  • 将“变量”与初始值绑定
  • 根据变量名称创建名称的 setter 方法

我在 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)

我正确地理解了“生产”和“生产-其他”的定义,“生产-11”功能有效(并将生产价值设置为 11),但最后一个不起作用。我在不同的浏览器中得到不同的错误。Chrome 显示“Uncaught SyntaxError: Unexpected token .”。Firefox “SyntaxError: missing ) after 形式参数”。

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 无效?

4

1 回答 1

2

问题是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))
于 2015-08-03T02:18:18.527 回答