2012-09-20 28 views
4

如何修改clojure fn或宏的arglist屬性?如何將a:arglists修改爲Clojure fn或宏?

(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

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

然後用相同的內容和不同的元數據重新定義了var

alter-meta!更改var上的元數據。該函數的元數據不相關,只有var。

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

雖然這是真的,但是'defn'允許你指定一個attr-map,這是一個乾淨的方式來完成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"} 

,或者你定義了var三倍頻與DEFN:

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

偷偷摸摸的!

3

到目前爲止,您不需要做任何醜陋的事情。如果你看一看DEFN自己arglists * ...

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是一個謊言。不要這樣做!

*請注意,我使用的是clojure.core/defn而非defn。它有所作爲,我不知道爲什麼。同樣與doc