clojure中的函数调用计数

clojure中的函数调用计数,clojure,functional-programming,Clojure,Functional Programming,您好,我正在寻找一种方法来计算clojure中的函数调用,以便例如,我可以找出调用频率最高的函数。理想情况下,我希望这对用户是透明的,这样,如果他们添加了一个他们不知道或不关心这个过程的函数。任何帮助都将不胜感激 先谢谢你 Michael您可以将呼叫计数存储在中,并使用以下方法将访问者附加到函数: 示例: ((::call-count (meta sqrt))) ;=> 0 (sqrt 0) ;=> 0.0 (sqrt 1)

您好,我正在寻找一种方法来计算clojure中的函数调用,以便例如,我可以找出调用频率最高的函数。理想情况下,我希望这对用户是透明的,这样,如果他们添加了一个他们不知道或不关心这个过程的函数。任何帮助都将不胜感激

先谢谢你
Michael

您可以将呼叫计数存储在中,并使用以下方法将访问者附加到函数:

示例:

((::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
(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
在某些情况下,这可能会导致相当大的速度减慢,但由于Clojure atoms是线程安全的,因此计数将始终正确更新。另一种方法可能是使用而不是,但哪一种更好取决于您的情况。如果你愿意,你甚至可以两者兼用

您可以使用
defcounted
宏来定义调用计数函数,使用
call count
函数来检索调用计数函数的调用计数,从而抽象出详细信息:

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

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

(defcounted sqrt [x]
  (Math/sqrt x))
示例:

((::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
(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
样式的参数,但我会让您自行决定,因为这与此问题是正交的。

您可以将调用计数存储在

示例:

((::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
(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
在某些情况下,这可能会导致相当大的速度减慢,但由于Clojure atoms是线程安全的,因此计数将始终正确更新。另一种方法可能是使用而不是,但哪一种更好取决于您的情况。如果你愿意,你甚至可以两者兼用

您可以使用
defcounted
宏来定义调用计数函数,使用
call count
函数来检索调用计数函数的调用计数,从而抽象出详细信息:

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

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

(defcounted sqrt [x]
  (Math/sqrt x))
示例:

((::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
(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
样式的参数,但我会让您自己做您认为合适的事情,因为它与这个问题是正交的