【问题标题】:How do I modify a :arglists to a Clojure fn or macro?如何将 :arglists 修改为 Clojure fn 或宏?
【发布时间】:2012-09-20 20:21:09
【问题描述】:

如何修改 clojure fn 或宏的 :arglist 属性?

(defn tripler ^{:arglists ([b])} [a] (* 3 a))

(defn ^{:arglists ([b])} quadrupler [a] (* 4 a))

% (meta #'tripler) => 
  {:arglists ([a]), :ns #<Namespace silly.testing>, :name tripler, :line 1, :file "NO_SOURCE_PATH"}

% (meta #'quadrupler) => 
  {:arglists ([a]), :ns #<Namespace silly.testing>, :name quadrupler, :line 1, :file "NO_SOURCE_PATH"}

好的,没有运气,所以我尝试执行以下操作。

(def tripler
  (with-meta trippler
    (assoc (meta #'tripler) :arglists '([c]))))

% (with-meta #'tripler) => 
  {:ns #<Namespace silly.testing>, :name tripler, :line 1, :file "NO_SOURCE_PATH"}

嗯,现在 :arglists 键不见了?好吧,我放弃了,我该怎么做?我只想修改 :arglists 的值。上面的示例使用了 defn,但我也想知道如何使用宏 (defmacro) 设置 :arglists。

【问题讨论】:

    标签: clojure macros arguments lisp-macros defn


    【解决方案1】:

    到目前为止,您不需要做任何像建议那样丑陋的事情。如果你看看defn 自己的参数列表...

    user=> (:arglists (meta #'clojure.core/defn))
    ([name doc-string? attr-map? [params*] prepost-map? body]
     [name doc-string? attr-map? ([params*] prepost-map? body) + attr-map?])
    

    您正在寻找attr-map。这是一个例子。

    user=> (defn foo
             "does many great things"
             {:arglists '([a b c] [d e f g])}
             [arg] arg)
    #'user/foo
    user=> (doc foo)
    -------------------------
    user/foo
    ([a b c] [d e f g])
      does many great things
    nil
    

    (在这种情况下,arglists 完全是一个谎言。不要那样做!)

    【讨论】:

    • 对于这个问题的未来发现者:这是正确的答案,其他的是解决方法或完全不正确。
    • @whereswalden 可能值得对其他人投反对票……
    【解决方案2】:

    alter-meta! 更改 var 上的元数据。函数上的元数据不相关,只有 var。

    (alter-meta! #'tripler assoc :arglists '([b]))
    

    【讨论】:

    • 虽然这是真的,defn 允许您指定属性映射,这是执行 Stephen 想要的更简洁的方法。请参阅下面的答案。
    【解决方案3】:

    defn 没有留下空间来破坏元数据,这是可以的,因为它只是一个包装 def 的宏。可以直接用def代替defn:

    core> (def  ^{:arglists '([b])} tripler (fn [a] (* 3 a)))
    #'core/tripler                                                                                 
    core> (meta #'tripler)
    {:arglists ([b]), :ns #<Namespace autotestbed.core>, :name tripler, :line 1, :file "NO_SOURCE_FILE"}
    

    或者你用 defn 定义 var 三元组:

    core> (defn tripler [a] (* 3 a))
    #'autotestbed.core/tripler                                                               
    

    然后用相同的内容和不同的元数据重新定义var:

    core> (def ^{:arglists '([b])} tripler  tripler)
    #'autotestbed.core/tripler                                                                                 
    autotestbed.core> (meta #'tripler)
    {:arglists ([b]), :ns #<Namespace autotestbed.core>, :name tripler, :line 1, :file "NO_SOURCE_FILE"}
    

    【讨论】:

      【解决方案4】:

      扩展 amalloy 的答案(请给予他信任):

      user=> (defn foo "prints bar" [] (println "bar"))
      #'user/foo
      
      user=> (doc foo)
      -------------------------
      user/foo
      ([])
        prints bar
      nil
      
      user=> (meta #'foo)
      {:arglists ([]), :ns #<Namespace user>, :name foo, :doc "prints bar", :line 1, :file "NO_SOURCE_PATH"}
      
      user=> (alter-meta! #'foo assoc :arglists '([blah]))
      {:arglists ([blah]), :ns #<Namespace user>, :name foo, :doc "prints bar", :line 1, :file "NO_SOURCE_PATH"}
      
      user=> (doc foo)
      -------------------------
      user/foo
      ([blah])
        prints bar
      nil
      
      user=> (meta #'foo)
      {:arglists ([blah]), :ns #<Namespace user>, :name foo, :doc "prints bar", :line 1, :file "NO_SOURCE_PATH"}
      
      user=> (foo)
      bar
      nil
      

      鬼鬼祟祟!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-28
        • 1970-01-01
        相关资源
        最近更新 更多