2016-05-05 5 views

Antwort

9

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")) 
4

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 ->