2016-05-05 28 views

risposta

9

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

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

Problemi correlati