Ich konnte den Unterschied zwischen Makroexpand und Makroexpand-1 nicht verstehen.Was ist der Unterschied zwischen Makroexpand und Makroexpand-1 in Clojure
Können Sie Beispiele bereitstellen?
Ich konnte den Unterschied zwischen Makroexpand und Makroexpand-1 nicht verstehen.Was ist der Unterschied zwischen Makroexpand und Makroexpand-1 in Clojure
Können Sie Beispiele bereitstellen?
Lassen Sie uns sagen, dass wir den folgenden Code haben:
(defmacro inner-macro [arg]
`(println ~arg))
(defmacro top-level-macro [arg]
`(inner-macro ~arg))
(defn not-a-macro [] nil)
Dann doc von macroexpand-1
sagt:
Wenn Form eines Makroform darstellt, die Expansion zurückkehrt, kehrt anderes Formular.
Tat es tut:
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)
Mit anderen Worten, macroexpand-1
macht nur einen Schritt von macroexpansion wenn Formular aus einer Makroform ist.
Dann doc von macroexpand
:
Wiederholt ruft macroexpand-1 auf Form, bis es nicht mehr eine Makroform darstellt, gibt es dann.
Beispiel:
user> (macroexpand '(top-level-macro "hello"))
(clojure.core/println "hello")
Was ist passiert? Sobald (top-level-macro "hello")
auf (user/inner-macro "hello")
erweitert wird, was eine Makroform ist, wird macroexpand
die Erweiterung noch einmal durchführen. Das Ergebnis der zweiten Erweiterung ist (clojure.core/println "hello")
. Es ist kein Makroformular, also gibt macroexpand
es nur zurück.
Also, nur das Dokument neu zu formulieren, wird macroexpand
rekursiv Expansion tun, bis Top-Level- Form keine Makroform ist.
Auch gibt es zusätzliche Anmerkung in macroexpand
‚s doc:
Hinweis weder macroexpand-1 noch macroexpand erweitern Makros in subforms.
Was bedeutet das? Lassen Sie uns sagen, dass wir noch ein Makro haben:
(defmacro subform-macro [arg]
`(do
(inner-macro ~arg)))
Lassen Sie uns versuchen, es zu erweitern:
user> (macroexpand-1 '(subform-macro "hello"))
(do (user/inner-macro "hello"))
user> (macroexpand '(subform-macro "hello"))
(do (user/inner-macro "hello"))
Da (do ...)
Form kein Makro macroexpand-1
und macroexpand
zurückkehren es einfach und nichts mehr. Erwarten Sie nicht, dass macroexpand
wird wie folgt vorgehen:
user> (macroexpand '(subform-macro "hello"))
(do (clojure.core/println "hello"))
der Unterschied ganz einfach. Zuallererst der Hintergrund: Wenn der Compiler den Makroaufruf sieht, versucht er, ihn entsprechend seiner Definition zu erweitern.Wenn der Code, der von diesem Makro generiert wird, andere Makros enthält, werden diese auch durch den Compiler usw. erweitert, bis der resultierende Code vollständig frei von Makros ist. So macroexpand-1
erweitert nur das oberste Makro und zeigt das Ergebnis (egal erzeugt es eine andere Makroaufrufe), während macroexpand
versucht, die Pipeline des Compilers zu folgen (teilweise Makros in Teilformularen nicht zu erweitern. Um die vollständige Erweiterung zu machen, sollten Sie sich ansehen clojure.walk/maxroexpand-all
).
kleines Beispiel:
user> (defmacro dummy [& body]
`(-> [email protected]))
#'user/dummy
dieses dumme Makro erzeugt den Anruf zu einem anderen Makro (->
)
user> (macroexpand-1 '(dummy 1 (+ 1)))
(clojure.core/-> 1 (+ 1))
macroexpand-1
erweitert nur dummy
, sondern hält ->
nicht expandierten
user> (macroexpand '(dummy 1 (+ 1)))
(+ 1 1)
macroexpand
expandiert dummy
und erweitert dann ->