我正在尝试(作为自学练习)创建Clojure宏,该宏将生成代码以将函数应用于整数序列并求和结果,例如

f(0)+ f(1)+ f(2)+ f(3)

这是我的尝试:

(defmacro testsum [func n]
  `(fn [x#] (+ ~@( map (fn [i] `(~func x#)) (range n)))))

但是x#gensym似乎出了问题,我最终得到了x的两个不同版本,因此该功能无法正常工作:
(macroexpand '(testsum inc 3))

给出:
(fn* ([x__809__auto__]
  (clojure.core/+
    (inc x__808__auto__)
    (inc x__808__auto__)
    (inc x__808__auto__))))

除了x ...的不同809和808版本外,这几乎就是我想要的。

我究竟做错了什么?我以为auto gensym就是为了实现这种目的而创建一个唯一的符号?有更好的方法吗?

最佳答案

foo# -style gensyms仅在创建它们的语法引用内有效。在您的代码中,两个x#是在不同的语法引用块中创建的:

(defmacro testsum [func n]
  `(fn [x#] (+ ~@( map (fn [i] `(~func x#)) (range n)))))
  ^- s-q1      ^-unquote       ^- s-q2

要解决此问题,请使用显式的(gensym)调用:
(defmacro testsum [func n]
  (let [x (gensym "x")]
    `(fn [~x] (+ ~@(map (fn [i] `(~func ~x)) (range n))))))

和宏扩展((macroexpand '(testsum inc 3))):
(fn* ([x4966] (clojure.core/+ (inc x4966) (inc x4966) (inc x4966))))

关于code-generation - 在Clojure宏中控制符号生成,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2840119/

10-11 20:18