5

如何修改 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。

4

4 回答 4

6

到目前为止,您不需要做任何像建议那样丑陋的事情。如果你看看defn's own arglists...</p>

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 完全是一个谎言。不要那样做!)

于 2012-11-01T20:56:03.910 回答
3

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

(alter-meta! #'tripler assoc :arglists '([b]))
于 2012-09-20T21:09:38.133 回答
2

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"}
于 2012-09-20T20:49:27.213 回答
-1

扩展 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

偷偷摸摸!

于 2012-09-20T21:39:23.307 回答