2010-06-01 10 views
5

Chciałbym mieć makro, które nazwałbym def-foo. Def-foo utworzy funkcję, a następnie doda tę funkcję do zestawu.Czy mogę utworzyć makro clojure, które pozwoli mi uzyskać listę wszystkich funkcji utworzonych przez makro?

Więc mogę zadzwonić

(def-foo bar ...) 

(def-foo baz ...) 

A wtedy nie będzie jakiś zestaw, np all-foos, które mógłbym nazwać:

all-foos 
=> #{bar, baz} 

Zasadniczo staram się tylko uniknąć powtarzania. Mógłbym oczywiście zdefiniować funkcje w normalny sposób (defn bar ...), a następnie napisać zestaw ręcznie.

Lepszą alternatywą i prostsze niż makro pomysłem byłoby zrobić:

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

Ale wciąż jestem ciekaw, czy jest to dobry sposób na makro pomysł, aby pracować.

Odpowiedz

5

Chcesz skończyć z zestawu który ma nazwy funkcji w nim (tj. zestaw symboli) lub zestaw zawierający vars (które rozwiązują funkcje)? Jeśli chcesz ten pierwszy, możesz dodać symbole do atomu w makrze podczas kompilacji, tak jak wersja Grega Harmana.

Jeśli chcesz to drugie, twoje makro musi rozwinąć się do kodu, który wykonuje zamiany atomów po zdefiniowaniu funkcji. Pamiętaj, że makra działają podczas kompilacji, a makro-rozwinięty wynik działa w czasie wykonywania; sama funkcja nie jest dostępna do czasu wykonania.

Jeśli chcesz mieć możliwość wywoływania funkcji z tego zestawu, musisz na przykład użyć tej ostatniej wersji.

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

Mają makro dodać nazwę nowej funkcji do odbiornika przed utworzeniem funkcji, tak jak poniżej:

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

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

Wynik:

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}> 
Powiązane problemy