我是Clojure的新手,在创建宏时遇到了一些麻烦。
Clojure中的代码,用于评估前1,000,000个整数的总和:
(apply + (range 1E6))
此基准代码评估总和,但也会打印此代码所需的纳秒数:
(let [start (System/nanoTime)
result (apply + (range 1E6))]
end (System/nanoTime)]
(println "Took:" (- end start) "ns")
result)
我将如何以下列形式与s.t.创建一个宏。 (benchmark expr)的值是expr的评估它打印以纳秒为单位评估expr所需的时间?
(defmacro benchmark [code]
...)
另外,关于宏如何工作,我有点困惑。为什么我们不能使用以下形式的普通函数?
(defn benchmark [code]
...)
答案 0 :(得分:1)
在您的情况下,宏和普通函数之间的主要区别在于参数评估顺序。传递给函数的参数在传递给函数体之前进行求值,而宏参数传递给宏体未评估(意味着宏体看到您输入的代码形式并且可以对纯代码进行操作)。小例子:
user>
(defn add2 [a]
(println "a is" a)
(+ a 2))
#'user/add2
user> (add2 (+ 10 10))
a is 20
22
user>
(defmacro add2-m [a]
(println "a is" a)
`(+ ~a 2))
#'user/add2-m
user> (add2-m (+ 10 10))
a is (+ 10 10)
22
这意味着编写日志记录功能将是不存在的,因为作为arg传递的基准测试代码将在第一个时间戳之前进行评估。
并且您想要的宏看起来像是这样的:
(defmacro bm [form]
`(let [start# (System/nanoTime)
result# ~form
end# (System/nanoTime)]
(println "Took:" (- end# start#) "ns")
result#))
在编译时扩展为以下内容:
;;(bm (apply + (range 1E6)))
;;=> Took: 131009572 ns
;;=> 499999500000
(let*
[start__6355__auto__
(. java.lang.System nanoTime)
result__6356__auto__
(apply + (range 1000000.0))
end__6357__auto__
(. java.lang.System nanoTime)]
(println "Took:" (- end__6357__auto__ start__6355__auto__) "ns")
result__6356__auto__)
答案 1 :(得分:0)
这是一个非常好的网站,可以了解单引号以及如何正确使用它们 https://8thlight.com/blog/colin-jones/2012/05/22/quoting-without-confusion.html
作为旁注,我确定这项任务的目的是自己尝试而不是复制答案:)。