Я пытаюсь (как самообучающееся осуществление) создать макрос 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__))))
Это в значительной степени точно, что я хочу кроме различных 809 и 808 версий x....
Что я делаю неправильно? Я думал, что автоматический gensym был предназначен для создания единственного уникального символа для точно этого вида цели? Существует ли лучший способ сделать это?
foo #
-стиль генсимов допустимы только внутри синтаксической кавычки где они были созданы. В вашем коде два 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))))