2010-06-01 8 views
5

Je voudrais avoir une macro que j'appellerai def-foo. Def-foo créera une fonction, puis ajoutera cette fonction à un ensemble.Puis-je créer une macro clojure qui me permettra d'obtenir une liste de toutes les fonctions créées par la macro?

Je pourrais appeler

(def-foo bar ...) 

(def-foo baz ...) 

Et puis il y aurait un certain ensemble, par exemple tout-foos, que je pourrais appeler:

all-foos 
=> #{bar, baz} 

Essentiellement, j'essaie juste d'éviter de me répéter. Je pourrais bien sûr définir les fonctions de la manière normale, (defn bar ...) puis écrire l'ensemble manuellement.

Une meilleure alternative, et plus simple que l'idée macro, serait de le faire:

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

Mais je suis toujours curieux de savoir s'il y a un bon moyen pour l'idée de travailler macro.

Répondre

5

Voulez-vous retrouver avec un ensemble qui a les noms de fonctions (c'est-à-dire un ensemble de symboles), ou un ensemble contenant des variables (qui se résolvent en fonctions)? Si vous voulez le premier, vous pouvez ajouter les symboles à un atome dans la macro au moment de la compilation, comme la version de Greg Harman.

Si vous voulez ce dernier, votre macro doit développer au code qui fait le permutation d'atomes après que la fonction est définie. Rappelez-vous que les macros s'exécutent à la compilation et que le résultat macro-développé s'exécute au moment de l'exécution; la fonction elle-même n'est pas disponible avant l'exécution.

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

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

Si vous voulez pouvoir appeler les fonctions de cet ensemble, par exemple, vous devez utiliser cette dernière version.

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

Demandez la macro ajouter le nom de la nouvelle fonction de votre appareil avant de créer la fonction, comme ceci:

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

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

Résultat:

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