2012-10-09 18 views
7

Per fare pratica, ho definitoProblemi con clojure quote-paren `(...) macro

(defmacro quote-paren 
    "body -> `(body)" 
    [& body] 
    `([email protected])) 

che ha la trasformazione previsto (quote-paren body) =>` `(corpo)`. Sembra di soddisfare alcuni test di base:

user=> (macroexpand-1 `(quote-paren 3 4 5)) 
(3 4 5) 
user=> (macroexpand-1 `(quote-paren println "hi")) 
(clojure.core/println "hi") 
user=> (macroexpand-1 `(quote-paren (println "hi"))) 
((clojure.core/println "hi")) 

Tuttavia, ho provato con questo do-while macro (modificato da here):

(defmacro do-while 
    [test & body] 
    (quote-paren loop [] 
    [email protected] 
    (when ~test 
     (recur)))) 

(def y 4) 
(do-while (> y 0) 
    (def y (dec y))) 

ma il risultato è

IllegalStateException Attempting to call unbound fn: #'clojure.core/unquote-splicing clojure.lang.Var$Unbound.throwArity (Var.java:43) 

Non lo capisco, perché da quello che posso vedere la macro `quote-paren 'funziona bene (con ~ @ body plug-in):

user=> (macroexpand-1 
     `(quote-paren loop [] 
      (def y (dec y)) 
      (when ~test 
       (recur)))) 

(clojure.core/loop [] (def user/y (clojure.core/dec user/y)) (clojure.core/when #<core$test [email protected]> (recur))) 

Ma provare a macroexpand do-while causa uno "unbound fn". C'è qualcosa di sottile che mi manca?

risposta

3

manca la sintassi-citazione prima quote-paren

user> (defmacro do-while 
    [test & body] 
    `(quote-paren loop [] 
    [email protected] 
    (when ~test 
     (recur)))) 
#'user/do-while 

che poi si espande correttamente:

user> (macroexpand '(do-while (> y 0) 
         (def y (dec y)))) 
(loop* [] (def y (dec y)) (clojure.core/when (> y 0) (recur))) 

e sembra funzionare:

user> (def y 4) 
#'user/y 
user> (do-while (> y 0) 
    (def y (dec y))) 
nil 
user> 
+1

e proprio come un commento a margine: con (def y ...) per il controllo del loop può avere conseguenze non intenzionali che non sono correlate a questa domanda ;-) –

+0

Hmm, hai ragione, ma questo tipo di sconfitte lo scopo del mio esercizio. Esiste comunque un virgolette che sostituisce '(quote-paren stuff)' con ''(cose)'? In breve, non è necessario scrivere 'nella definizione macro. – spacingissue

+0

Ho provato a sostituire '(quote-paren stuff)' con '(quote (cose))' ma sembra smettere di riconoscere le variabili; che è '(defmacro do-while [prova e corpo] (citazione (anello [] ~ @ corpo (quando ~ prova (ripresentarsi)))))' e l'esecuzione si traduce in 'CompilerException java.lang. RuntimeException: Impossibile risolvere il simbolo: body in questo contesto, compilando: (NO_SOURCE_PATH: 58) 'Se questo è il modo migliore per affrontare un'altra domanda, comunque, capirò. – spacingissue