2012-10-09 22 views
7

Para la práctica, he definidoProblemas con clojure Cotización en paren `(...) macro

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

que tiene la transformación esperada (quote-paren body) =>` `(cuerpo)`. Se parece satisfacer algunas pruebas básicas:

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

Sin embargo, he estado probando con este do-while macro (modificado de 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))) 

pero el resultado es

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

No entiendo esto, porque por lo que puedo ver, la macro `quote-paren 'funciona bien (con ~ @ cuerpo enchufado):

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

Pero al intentar macroexpandir do-while provoca un "unbound fn". ¿Hay algo sutil que me estoy perdiendo?

Respuesta

3

falta la sintaxis de la cotización antes quote-paren

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

que luego se expande adecuadamente:

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

y parece que funciona:

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

y así como un comentario al margen: el uso de (def y ...) para control de bucle puede tener consecuencias involuntarias que no están relacionadas con esta pregunta ;-) –

+0

Hmm, tienes razón, pero ese tipo de derrotas el propósito de mi ejercicio. ¿Hay alguna forma de hacer una cita-paren que reemplace '(quote-paren stuff)' con ''(stuff)'? En resumen, no es necesario escribir 'en la definición de macro. – spacingissue

+0

He intentado reemplazar '(quote-paren stuff)' con '(quote (cosas))' pero parece dejar de reconocer las variables; es decir '(defmacro do-while [prueba y cuerpo] (cita (circular [] ~ @ cuerpo (cuando ~ prueba (reaparecer)))))' y funcionando resultados en 'java.lang CompilerException. RuntimeException: no se puede resolver el símbolo: body en este contexto, compilando: (NO_SOURCE_PATH: 58) 'Pero si esto se aborda mejor en otra pregunta, lo entendería. – spacingissue