mik*_*era 19 macros code-generation symbols clojure
我正在尝试(作为一种自学练习)创建一个Clojure宏,它将生成代码以将函数应用于整数序列并对结果求和,例如
f(0)+ f(1)+ f(2)+ f(3)
这是我的尝试:
(defmacro testsum [func n]
`(fn [x#] (+ ~@( map (fn [i] `(~func x#)) (range n)))))
Run Code Online (Sandbox Code Playgroud)
然而,x#gensym似乎出现了问题,我最终得到了两个不同版本的x,因此该函数不起作用:
(macroexpand '(testsum inc 3))
Run Code Online (Sandbox Code Playgroud)
得到:
(fn* ([x__809__auto__]
(clojure.core/+
(inc x__808__auto__)
(inc x__808__auto__)
(inc x__808__auto__))))
Run Code Online (Sandbox Code Playgroud)
除了不同的809和808版本的x之外,这几乎是我想要的......
我究竟做错了什么?我认为自动gensym旨在为这种目的创造一个独特的符号?有没有更好的方法呢?
Mic*_*zyk 24
foo#样式gensyms仅在创建它们的语法引号内有效.在您的代码中,两个x#s是在不同的语法 - 引用块中创建的:
(defmacro testsum [func n]
`(fn [x#] (+ ~@( map (fn [i] `(~func x#)) (range n)))))
^- s-q1 ^-unquote ^- s-q2
Run Code Online (Sandbox Code Playgroud)
要解决此问题,请使用显式(gensym)调用:
(defmacro testsum [func n]
(let [x (gensym "x")]
`(fn [~x] (+ ~@(map (fn [i] `(~func ~x)) (range n))))))
Run Code Online (Sandbox Code Playgroud)
而宏扩展((macroexpand '(testsum inc 3))):
(fn* ([x4966] (clojure.core/+ (inc x4966) (inc x4966) (inc x4966))))
Run Code Online (Sandbox Code Playgroud)