2010-06-01 9 views
5

Me gustaría tener una macro a la que llamaré def-foo. Def-foo creará una función y luego agregará esta función a un conjunto.¿Puedo hacer una macro de clojure que me permita obtener una lista de todas las funciones creadas por la macro?

Así que podría llamar

(def-foo bar ...) 

(def-foo baz ...) 

Y entonces no habría algún conjunto, por ejemplo, All-Foos, que podría llamar:

all-foos 
=> #{bar, baz} 

Esencialmente, estoy tratando de evitar repetirme. Por supuesto, pude definir las funciones de la manera normal (defn bar ...) y luego escribir el conjunto manualmente.

Una alternativa mejor y más simple que la idea macro, habría que hacer:

(def foos #{(defn bar ...) (defn baz ...)}) 

pero todavía estoy curioso en cuanto a si existe una buena manera para que la idea macro funcione.

Respuesta

5

¿Quieres terminar con un conjunto que tiene los nombres de las funciones en él (es decir, un conjunto de símbolos), o un conjunto que contiene vars (que se resuelven en las funciones)? Si quiere lo primero, puede agregar los símbolos a un átomo en la macro en tiempo de compilación, como la versión de Greg Harman.

Si desea lo último, su macro debe expandirse al código que realiza el intercambio de átomos después de que se define la función. Recuerde que las macros se ejecutan en tiempo de compilación y el resultado macro expandido se ejecuta en tiempo de ejecución; la función en sí no está disponible hasta el tiempo de ejecución.

(def all-foos (atom #{})) 

(defmacro def-foo [x] 
    `(let [var# (defn ~x [] (println "I am" '~x))] 
    (swap! all-foos conj var#))) 

Si desea poder llamar a las funciones de este conjunto, por ejemplo, necesita utilizar esta última versión.

user> (def-foo foo) 
#{#'user/foo} 
user> (def-foo bar) 
#{#'user/foo #'user/bar} 
user> ((first @all-foos)) 
I am foo 
nil 
5

que la macro añadir el nombre de la nueva función para el reproductor antes de la creación de la función, así:

(def *foos* (atom (hash-set))) 

(defmacro def-foo [name] 
    (swap! *foos* conj name) 
    `(defn ~name 
    [] 
    (println "This is a foo!"))) 

Resultado:

user=> (def-foo bar) 
#'user/bar 
user=> (def-foo baz) 
#'user/baz 
user=> (bar) 
This is a foo! 
nil 
user=> (baz) 
This is a foo! 
nil 
user=> *foos* 
#<[email protected]: #{baz bar}> 
Cuestiones relacionadas