Управление поколением символа в макросах Clojure

Я пытаюсь (как самообучающееся осуществление) создать макрос 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 был предназначен для создания единственного уникального символа для точно этого вида цели? Существует ли лучший способ сделать это?

19
задан mikera 15 May 2010 в 12:37
поделиться

1 ответ

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))))
24
ответ дан 30 November 2019 в 04:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: