2016-12-13 8 views
1

こんにちは、私はclojureで関数呼び出しを数えるメソッドを探しています。たとえば、どの関数が最も頻繁に呼び出されるかを調べることができます。理想的には、私はこれをユーザーに透過的にして、機能を追加しても、このプロセスを知らないか気にかけないようにしたいと思っています。どんな助けでも大歓迎です。clojureで関数を呼び出す

あなたはatomに呼び出し回数を格納しwith-metaを使用して関数にアクセサを添付することができ、事前 マイケル

答えて

5

であなたに感謝:

(def sqrt 
    (let [n (atom 0)] 
    (with-meta 
     (fn [x] 
     (swap! n inc) 
     (Math/sqrt x)) 
     {::call-count (fn [] @n)}))) 

例:

((::call-count (meta sqrt))) ;=> 0 

(sqrt 0)      ;=> 0.0 
(sqrt 1)      ;=> 1.0 
(sqrt 2)      ;=> 1.4142135623730951 

((::call-count (meta sqrt))) ;=> 3 

(sqrt 3)      ;=> 1.7320508075688772 
(sqrt 4)      ;=> 2.0 
(sqrt 5)      ;=> 2.23606797749979 

((::call-count (meta sqrt))) ;=> 6 

この場合によっては大幅に減速することがありますが、カウントは常に正しく更新されます。なぜなら、Clojureアトムスレッドセーフです。別のアプローチは、derefではなくadd-watchを使用することができますが、どちらがあなたの状況によりますか。あなたがしたい場合は、両方を使用することもできます。

コールカウント関数の呼び出し回数を取得するには、コール・カウント機能や call-count関数を定義するマクロ defcountedと詳細離れてすることができます抽象

(defmacro defcounted [sym params & body] 
    `(def ~sym 
    (let [n# (atom 0)] 
     (with-meta 
     (fn ~params 
      (swap! n# inc) 
      [email protected]) 
     {::call-count (fn [] @n#)})))) 

(defn call-count [f] 
    ((::call-count (meta f)))) 

(defcounted sqrt [x] 
    (Math/sqrt x)) 

例:

(call-count sqrt) ;=> 0 

(sqrt 0)   ;=> 0.0 
(sqrt 1)   ;=> 1.0 
(sqrt 2)   ;=> 1.4142135623730951 

(call-count sqrt) ;=> 3 

(sqrt 3)   ;=> 1.7320508075688772 
(sqrt 4)   ;=> 2.0 
(sqrt 5)   ;=> 2.23606797749979 

(call-count sqrt) ;=> 6 

また、ここでは、varではなく関数自体にメタデータを添付しているので、この手法を匿名関数にも拡張できます。

明らかにdefcountedにはdefnの機能がほとんどないため、ユーザーにとってはあまり透明ではありません。この問題を修正するには、clojure.specを使用してdefnスタイルの引数をより簡単に解析することができますが、この質問とは正反対のので、適切に行うようにしておきます。

関連する問題