为什么时间需要是一个宏?

Why does time need to be a macro?

Clojure source code给出了time

的如下定义
(defmacro time
  "Evaluates expr and prints the time it took.  Returns the value of
 expr."
  {:added "1.0"}
  [expr]
  `(let [start# (. System (nanoTime))
         ret# ~expr]
     (prn (str "Elapsed time: " (/ (double (- (. System (nanoTime)) start#)) 1000000.0) " msecs"))
     ret#))

为什么这需要是一个宏?一个函数做不到怎么办?

因为函数在开始使用它们之前会对其参数求值。您可以将 time 写成函数并尝试调用它:

(defn my-time [expr]
  (let [start (System/nanoTime)
        ret expr]
    (prn (str "Elapsed time: " (/ (double (- (System/nanoTime) start)) 1000000.0) " msecs"))
    ret))

(my-time (Thread/sleep 1000))
"Elapsed time: 0.005199 msecs"
=> nil

time 宏比较:

(time (Thread/sleep 1000))
"Elapsed time: 1000.1222 msecs"
=> nil

函数 my-time 评估了参数 (Thread/sleep 1000),符号 expr 获得了值 nil,然后该函数的主体发生了 - 之后不久调用了两个 (System/nanoTime)彼此,因为已经计算了 expr 的值。

time 未计算 (Thread/sleep 1000),但扩展为:

(macroexpand `(time (Thread/sleep 1000)))
=>
(let*
 [start__6136__auto__ (. java.lang.System (clojure.core/nanoTime)) ret__6137__auto__ (java.lang.Thread/sleep 1000)]
 (clojure.core/prn
  (clojure.core/str
   "Elapsed time: "
   (clojure.core//
    (clojure.core/double (clojure.core/- (. java.lang.System (clojure.core/nanoTime)) start__6136__auto__))
    1000000.0)
   " msecs"))
 ret__6137__auto__)

函数的调用顺序为:(System/nanoTime)(Thread/sleep 1000) 和其他 (System/nanoTime),returns 正确时间。