【问题标题】:Can I make a clojure macro that will allow me to get a list of all functions created by the macro?我可以制作一个 clojure 宏,让我可以获取该宏创建的所有函数的列表吗?
【发布时间】:2011-02-26 13:23:15
【问题描述】:

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

所以我可以打电话

(def-foo bar ...)

(def-foo baz ...)

然后会有一些设置,例如all-foos,我可以称之为:

all-foos
=> #{bar, baz}

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

比宏观想法更好且更简单的方法是:

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

但我仍然很好奇宏观想法是否有好的方法。

【问题讨论】:

    标签: macros clojure dry


    【解决方案1】:

    你想最终得到一个包含函数名称的集合(即一组符号),还是包含变量的集合(解析为函数)?如果您想要前者,您可以在编译时将符号添加到宏中的原子,如 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
    

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 2021-04-25
        • 1970-01-01
        • 1970-01-01
        • 2019-09-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多