Non ho potuto capire la differenza tra macroexpand e macroexpand-1.Qual è la differenza tra macroexpand e macroexpand-1 in Clojure
Potrebbe fornire degli esempi?
Non ho potuto capire la differenza tra macroexpand e macroexpand-1.Qual è la differenza tra macroexpand e macroexpand-1 in Clojure
Potrebbe fornire degli esempi?
Diciamo che abbiamo il seguente codice:
(defmacro inner-macro [arg]
`(println ~arg))
(defmacro top-level-macro [arg]
`(inner-macro ~arg))
(defn not-a-macro [] nil)
Poi, doc di macroexpand-1
dice:
Se modulo rappresenta una forma di macro, restituisce la sua espansione, altro restituisce modulo.
Infatti, lo fa:
user> (macroexpand-1 '(inner-macro "hello"))
(clojure.core/println "hello")
user> (macroexpand-1 '(top-level-macro "hello"))
(user/inner-macro "hello")
user> (macroexpand-1 '(not-a-macro))
(not-a-macro)
In altre parole, macroexpand-1
fa solo un passo di macroexpansion se forma fornita è una forma macro.
Poi, doc macroexpand
:
chiama ripetutamente macroexpand-1 sulla forma fino a che non rappresenta una forma macro, quindi restituisce.
Esempio:
user> (macroexpand '(top-level-macro "hello"))
(clojure.core/println "hello")
Che cosa è successo? Non appena (top-level-macro "hello")
si espande a (user/inner-macro "hello")
, che è il modulo macro, macroexpand
eseguirà nuovamente l'espansione. Il risultato della seconda espansione è (clojure.core/println "hello")
. Non è un modulo macro, quindi lo macroexpand
lo restituisce.
Così, tanto per riformulare il doc, macroexpand
modo ricorsivo fare di espansione fino livello superiore forma non è una forma di macro.
Inoltre c'è nota aggiuntiva nel doc macroexpand
s':
Nota né macroexpand-1 né macroexpand espandono macro in sottomoduli.
Che cosa significa? Diciamo che abbiamo un altro macro:
(defmacro subform-macro [arg]
`(do
(inner-macro ~arg)))
Proviamo a espanderlo:
user> (macroexpand-1 '(subform-macro "hello"))
(do (user/inner-macro "hello"))
user> (macroexpand '(subform-macro "hello"))
(do (user/inner-macro "hello"))
Dal momento che, (do ...)
modulo non è una macro macroexpand-1
e macroexpand
semplicemente restituirlo e niente di più. Non si aspettano che macroexpand
farà il seguente:
user> (macroexpand '(subform-macro "hello"))
(do (clojure.core/println "hello"))
la differenza è abbastanza semplice. Prima di tutto lo sfondo: quando il compilatore vede la chiamata alla macro cerca di espanderla secondo la sua definizione.Se il codice, generato da questa macro contiene altre macro, vengono anche espanse dal compilatore e così via, fino a quando il codice risultante è totalmente privo di macro. Quindi, macroexpand-1
espande appena la macro più in alto e mostra il risultato (non importa generare altre macro chiamate), mentre macroexpand
prova a seguire la pipeline del compilatore (parzialmente, non espandendo le macro in sottomaschera. Per fare l'espansione completa dovresti dare un'occhiata a clojure.walk/maxroexpand-all
).
piccolo esempio:
user> (defmacro dummy [& body]
`(-> [email protected]))
#'user/dummy
questo stupido macro genera la chiamata a un'altra macro (->
)
user> (macroexpand-1 '(dummy 1 (+ 1)))
(clojure.core/-> 1 (+ 1))
macroexpand-1
solo espande dummy
, ma mantiene ->
non espansa
user> (macroexpand '(dummy 1 (+ 1)))
(+ 1 1)
macroexpand
si espande dummy
e quindi espande ->