2012-09-20 2 views
4

clojure fn 또는 매크로의 : arglist 속성을 어떻게 수정합니까?: 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을 사용하지만 매크로를 사용하는 arglists (defmacro)를 설정하는 방법을 알고 싶습니다.

답변

4
:

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

는 다음 같은 내용과 다른 메타 데이터와 VAR을 재정의 : 당신은 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에 체배기를 정의

alter-meta!은 var의 메타 데이터를 변경합니다. 함수의 메타 데이터는 관련이 없으며 var 만 amalloy의 대답에 확장

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

사실,'defn'은 attr-map을 지정할 수있게 해 주며, 이는 스티븐이 원하는 것을보다 깨끗한 방법으로 수행합니다. 아래 내 대답을 참조하십시오. –

3

defn은 단지 def을 감싸는 매크로이기 때문에 메타 데이터를 mangle하기위한 공간을 남겨 두지 않습니다.

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

(그에게 신용을 적어주세요) :

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 

이 경우 arglist는 총 거짓말입니다. 그렇게하지 마!

* defn이 아닌 clojure.core/defn을 사용했음을 유의하십시오. 그것은 차이를 만들어 내고 왜 그런지 모르겠습니다. 마찬가지로 doc.