La respuesta está contenido en la pregunta: solo usa gensym
como lo haría si Clojure no tuviera auto gensyms.
(defmacro make [v & body]
(let [value-sym (gensym)]
`(let [~value-sym ~(some-calc v)]
[email protected](replace {:value value-sym} body))))
Tenga en cuenta que no estoy seguro de si realmente desea ~
o [email protected]
aquí - depende si body
se supone que es una secuencia de expresiones para ejecutar en el let
, o una secuencia de argumentos para una sola función llamada. Pero [email protected]
sería mucho más intuitivo/normal, así que eso es lo que voy a adivinar.
Si esta macro es anafórica es un poco cuestionable: definitivamente introduciendo nv
en el alcance de la llamada fue, pero básicamente no fue intencional, así que diría que no. En mi versión revisada, ya no estamos introduciendo nv
ni nada parecido, pero estamos "mágicamente" reemplazando :value
con v
. Sin embargo, solo hacemos eso en el nivel más alto del cuerpo, así que no es como introducir un alcance real, diría que es más como hacer que el código del cliente se rompa inesperadamente en casos de esquina. Para obtener un ejemplo de cómo puede surgir este comportamiento engañoso, imagine que uno de los elementos de body
es . No será reemplazado por la macro, y se expandirá a (inc :value)
, lo que nunca tendrá éxito. Por lo tanto, en su lugar, recomendaría una macro anafórica real , que presenta un alcance real para un símbolo.Algo así como
(defmacro make [v & body]
`(let [~'the-value ~(some-calc v)]
[email protected]))
Y entonces la persona que llama simplemente puede usar the-value
en su código, y se comporta como un auténtico, local regular de unión: la macro lo introduce por arte de magia, pero no tiene ningún otro trucos especiales .
No estoy seguro si puede llamarlo anafórico: para serlo, 'nv' debe referirse a alguna parte del formulario de macro invocación. Si factoriza 'some-calc' del macro cuerpo, entonces tendrá una invocación anafórica más apropiada:' (make (some-calc x) (do-something-to nv)) 'donde' nv' se refiere a ' (algo-calc x) '. En su caso, tendrá '(make x (do-some-thing-to nv))', pero luego 'nv' no se referirá directamente a nada en el formulario de macro invocación. – skuro
@skuro: Ya veo, básicamente esto es lo peor de ambos mundos: introducir un nuevo símbolo que, sin embargo, permanecerá oculto hasta que alguien lo redefina accidentalmente. Hf rastrear ese error :) Afortunadamente, un 'gensym' explícito según la sugerencia de amalloy resuelve este problema. –