La risposta è contenuto nella domanda: basta usare gensym
come faresti se Clojure non avesse auto-gensyms.
(defmacro make [v & body]
(let [value-sym (gensym)]
`(let [~value-sym ~(some-calc v)]
[email protected](replace {:value value-sym} body))))
Nota che io non sono sicuro se si vuole veramente ~
o [email protected]
qui - dipende se body
si suppone essere una sequenza di espressioni da eseguire nel let
, oppure una sequenza di argomenti per una singola funzione chiamata. Ma [email protected]
sarebbe molto più intuitivo/normale, quindi è quello che intendo indovinare.
Se questa macro è anaforica è un po 'discutibile: sicuramente l'introduzione di nv
nello scope chiamante era, ma sostanzialmente non intenzionale, quindi direi di no. Nella mia versione rivista, non stiamo più introducendo nv
o qualcosa del genere, ma stiamo "magicamente" sostituendo :value
con v
. Lo facciamo solo al livello più alto del corpo, quindi, non è come introdurre un vero ambito - direi che è più come far si che il codice del client si interrompa inaspettatamente nei casi d'angolo.
Per un esempio di come questo comportamento ingannevole può emergere, immagina che uno degli elementi di body
sia (inc :value)
. Non verrà sostituito dalla macro e si espanderà a (inc :value)
, che non ha mai successo. Quindi preferirei una macro anaphorica reale , che introduce un vero ambito per un simbolo.Qualcosa di simile
(defmacro make [v & body]
`(let [~'the-value ~(some-calc v)]
[email protected]))
E poi il chiamante può semplicemente usare the-value
nel loro codice, e si comporta proprio come un vero, regolare locale vincolante: la macro introduce per magia, ma non hanno altri trucchi speciali .
Non so se è possibile chiamarlo anaphoric: per essere così, 'nv' dovrebbe fare riferimento ad alcune parti del modulo di invocazione macro. Se si calcola 'some-calc' dal corpo della macro, si avrà una invocazione anaforica più appropriata:' (make (some-calc x) (do-something-to nv)) 'dove' nv' si riferisce a ' (some-calc x) '. Nel tuo caso avrai '(make x (do-some-thing-to-nv))', ma in questo caso 'nv' non si riferirebbe direttamente a qualcosa nel modulo di invocazione macro. – skuro
@skuro: Vedo, quindi in pratica questo è il peggiore dei due mondi - introducendo un nuovo simbolo che resterà comunque nascosto finché qualcuno non lo ridefinirà accidentalmente. Hf che tiene traccia di questo errore :) Fortunatamente, un esplicito 'gensym' come da suggerimento di amalloy risolve questo problema. –