代码之家  ›  专栏  ›  技术社区  ›  Rob Lachlan

我可以做一个clojure宏,它允许我获取由宏创建的所有函数的列表吗?

  •  5
  • Rob Lachlan  · 技术社区  · 16 年前

    我想要一个宏,我称之为def foo。def foo将创建一个函数,然后将该函数添加到集合中。

    所以我可以打电话

    (def-foo bar ...)
    
    (def-foo baz ...)
    

    然后会有一些集合,例如所有的foo,我可以称之为:

    all-foos
    => #{bar, baz}
    

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

    一个比宏观观点更简单的更好的选择是:

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

    但我仍然很好奇,是否有一个好的方式,宏观的想法工作。

    2 回复  |  直到 16 年前
        1
  •  5
  •   Brian Carper    16 年前

    您希望以包含函数名的集合(即一组符号)或包含var的集合(解析为函数)结束吗?如果需要前者,可以在编译时将符号添加到宏中的一个原子中,比如GregHarman的版本。

    如果需要后者,则宏必须扩展到在定义函数后执行原子交换的代码。记住,宏在编译时运行,宏扩展的结果在运行时运行;函数本身在运行时之前不可用。

    (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
    
        2
  •  5
  •   G__    16 年前

    在创建函数之前,让宏将新函数的名称添加到集合中,如下所示:

    (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*
    #<Atom@186b11c: #{baz bar}>
    
    推荐文章