2011-09-05 11 views
6

Estoy tratando de escribir una macro en Clojure que permita la evaluación de una serie de expresiones simples "def". Soy un n00b cuando se trata de macros. La idea es queLooping through args of macro

(my-defs y1 1 
    y2 "taco") 

debería ampliar a

(do (def y1 1) (def y2 "taco")) 

El siguiente código realiza esto para el caso especial de dos defs

(defmacro my-defs 
    [& args] 
    `(do 
    (def ~(first args) ~(second args)) 
    (def ~(nth args 2) ~(nth args 3)))) 

lo cual es bueno, pero estoy teniendo problemas para generalizar esta. Probé algunas cosas ingenuas que involucraban bucles a través de los enlaces de los elementos de (partition 2 args) pero siempre recibí basura (sé que esto no es muy específico, pero la diversidad y el alcance de la basura parecían demasiado como para informar aquí). ¿Cómo doy un vuelco sobre estos y evalúo mis defs?

P.S. La macro my-defs es un juguete. Lo que realmente quiero lograr al final es una pequeña macro auxiliar para instanciar un conjunto de instancias multimétodo. Actualmente tengo grandes trozos de código que se parecen a

(defmethod f [A B] [x] "AB") 
(defmethod f [A A] [x] "AA") 
(defmethod f [C B] [x] "CB") 

que es un poco desagradable. Sería bueno si pudiera hacer algo como

(defmethods f 
    [A B] [x] "AB" 
    [A A] [x] "AA" 
    [C B] [x] "CB") 

en su lugar.

Respuesta

5

Me parece que está buscando ~ @ macro expansion/unquote.

(defmacro defmethods [n & defs] 
    `(do [email protected](map (fn [[a1 a2 a3]] 
        `(def ~n ~a1 ~a2 ~a3)) 
       (partition 3 defs)))) 
+0

¡Gracias, he escrito mis defmethods ahora! –

+1

Creo que este patrón es más fácil de escribir ya sea '(cons 'do (para [[xyz] (partición 3 args)] ...)' o '\' (do ~ @ (for ...)) \ ' '.Mapa rompe el flujo de cosas, y usar una comilla hacia atrás y' ~ @ 'solo para obtener una desventaja hace que el código parezca confuso. – amalloy

+0

@amalloy. Gracias por la sugerencia. (Do ~ @ (for ...)) Se ve mejor. –