2010-06-01 92 views
5

我想要一个叫做def-foo的宏。 Def-foo将创建一个函数,然后将这个函数添加到一个集合中。我可以制作一个clojure宏,它可以让我获得宏创建的所有函数的列表吗?

所以我可以打电话给

(def-foo bar ...) 

(def-foo baz ...) 

然后会有一些设置,例如我可以打电话给他:

all-foos 
=> #{bar, baz} 

基本上,我只是想避免重复自己。我当然可以用正常的方式定义函数,(定义栏...),然后手动编写该集合。

一个更好的选择,而不是宏观的想法比较简单,是做:

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

但我还是好奇,是否有宏观思想工作的好办法。

回答

5

你想用一组落得有它的函数名称(即一组符号),还是一个包含变量(解析为函数)的集合?如果你想要前者,你可以在编译时将这些符号添加到宏中的一个原子,就像Greg Harman的版本一样。

如果你想要后者,你的宏必须扩展到定义函数后进行原子交换的代码。请记住,宏在编译时运行,宏扩展结果在运行时运行;该功能本身在运行时间之前不可用。

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

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

例如,如果您希望能够调用此组中的函数,则需要使用后者的版本。

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

进行宏观创造功能,像这样,在新的函数的名称添加到您的设置:

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

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

结果:

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}> 
相关问题