2016-12-13 3 views
1

Привет Я ищу метод для подсчета вызовов функций в clojure, чтобы, например, я мог узнать, какие функции вызывают чаще всего. В идеале я бы хотел, чтобы это было прозрачным для пользователей, чтобы, если они добавляют функцию, они не знают или не заботятся об этом процессе. Любая помощь будет принята с благодарностью.подсчет вызовов функций в clojure

Благодарим Вас заранее Майкл

ответ

5

Вы можете сохранить количество вызовов в atom и прикрепить аксессора к функции с помощью with-meta:

(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 s являются потокобезопасными. Другой подход может заключаться в использовании add-watch, а не deref, но который лучше зависит от вашей ситуации. Вы даже можете использовать оба варианта, если хотите.

Вы можете абстрагироваться от детали с defcounted макросов для определения функций вызова подсчетом и call-count функцию, чтобы получить количество вызовов функции вызова подсчетом:

(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, но я оставлю это для вас, как вам кажется, так как он ортогонален этому вопросу.

Смежные вопросы