2010-06-01 4 views
5

Ich hätte gerne ein Makro, das ich def-foo nennen werde. Def-foo erstellt eine Funktion und fügt diese Funktion zu einem Set hinzu.Kann ich ein Clojure-Makro erstellen, mit dem ich eine Liste aller vom Makro erstellten Funktionen abrufen kann?

So kann ich rufen

(def-foo bar ...) 

(def-foo baz ...) 

Und dann gäbe es einigen Satz sein, z.B. All-Foos, die ich nennen könnte:

all-foos 
=> #{bar, baz} 

Im Grunde versuche ich nur zu vermeiden, mich zu wiederholen. Ich könnte natürlich die Funktionen auf normale Weise definieren (defn bar ...) und dann das Set manuell schreiben.

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

Aber ich bin immer noch neugierig, ob ein guter Weg für die Makro-Idee gibt es zu arbeiten:

Eine bessere Alternative, und einfacher als die Makro Idee, zu tun wäre.

Antwort

5

Haben Sie mit einem Satz wollen am Ende das hat die Namen von Funktionen (dh eine Menge von Symbolen) oder eine Menge, die vars enthält (die zu Funktionen auflösen)? Wenn Sie ersteres wollen, können Sie die Symbole zu einem Atom im Makro zur Kompilierzeit hinzufügen, wie Greg Harmans Version.

Wenn Sie Letzteres möchten, muss Ihr Makro zu Code erweitert werden, der das Atom-Swapping ausführt, nachdem die Funktion definiert ist. Denken Sie daran, dass Makros zur Kompilierungszeit ausgeführt werden und das Makroexpansionsergebnis zur Laufzeit ausgeführt wird. Die Funktion selbst ist erst zur Laufzeit verfügbar.

Wenn Sie beispielsweise die Funktionen in diesem Set aufrufen möchten, müssen Sie die letztere Version verwenden.

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

Haben das Makro den Namen der neuen Funktion zu Ihrem Satz hinzufügen, bevor die Funktion zu schaffen, etwa so:

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

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

Ergebnis:

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