2010-06-01 12 views
5

Mi piacerebbe avere una macro che chiamerò def-foo. Def-foo creerà una funzione e quindi aggiungerà questa funzione a un set.Posso creare una macro clojure che mi consenta di ottenere un elenco di tutte le funzioni create dalla macro?

Così ho potuto chiamare

(def-foo bar ...) 

(def-foo baz ...) 

E poi ci sarebbe qualche insieme, per esempio all-foos, che potrei chiamare:

all-foos 
=> #{bar, baz} 

In sostanza, sto solo cercando di evitare di ripetermi. Naturalmente potrei definire le funzioni nel modo normale, (defn bar ...) e quindi scrivere manualmente il set.

Un'alternativa migliore, e più semplice l'idea macro, sarebbe quella di fare:

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

ma io sono ancora curioso di vedere se v'è un buon modo per l'idea macro di lavorare.

risposta

5

Vuoi finire con un set che ha i nomi delle funzioni in esso (cioè un insieme di simboli), o un set contenente vars (che risolvono le funzioni)? Se vuoi il primo, puoi aggiungere i simboli ad un atomo nella macro in fase di compilazione, come nella versione di Greg Harman.

Se si desidera quest'ultimo, la macro deve espandersi al codice che esegue lo scambio atomico dopo la definizione della funzione. Ricorda che le macro vengono eseguite in fase di compilazione e il risultato espanso in macro viene eseguito in fase di esecuzione; la funzione stessa non è disponibile fino al momento dell'esecuzione.

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

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

Se si vuole essere in grado di chiamare le funzioni in questo set, ad esempio, è necessario utilizzare quest'ultima versione.

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

Avere la macro aggiungere il nome della nuova funzione per il set prima di creare la funzione, in questo modo:

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

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

Risultato:

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}> 
Problemi correlati