【发布时间】:2014-12-24 22:19:55
【问题描述】:
我编写了一个快速而肮脏的宏来计时 lisp 代码。但是,我现在面临的问题是我想在函数中包含一个可选的输出流。但是,我不知道如何在defmacro 中同时使用&optional 和&body 参数。我查找了示例,但只找到了我认为我理解的defun 的示例。我无法弄清楚为什么这对我来说失败了。任何提示:
(defmacro timeit (&optional (out-stream *standard-output*) (runs 1) &body body)
"Note that this function may barf if you are depending on a single evaluation
and choose runs to be greater than one. But I guess that will be the
caller's mistake instead."
(let ((start-time (gensym))
(stop-time (gensym))
(temp (gensym))
(retval (gensym)))
`(let ((,start-time (get-internal-run-time))
(,retval (let ((,temp))
(dotimes (i ,runs ,temp)
(setf ,temp ,@body))))
(,stop-time (get-internal-run-time)))
(format ,out-stream
"~CTime spent in expression over ~:d iterations: ~f seconds.~C"
#\linefeed ,runs
(/ (- ,stop-time ,start-time)
internal-time-units-per-second)
#\linefeed)
,retval)))
这就是我打算使用代码的方式:
(timeit (+ 1 1)) ; Vanilla call
(timeit *standard-output* (+ 1 1)) ; Log the output to stdout
(timeit *standard-output* 1000 (+ 1 1)) ; Time over a 1000 iterations.
我认为从defmacro 上的hyperspec 中找到的这个是一个类似的想法。
(defmacro mac2 (&optional (a 2 b) (c 3 d) &rest x) `'(,a ,b ,c ,d ,x)) => MAC2
(mac2 6) => (6 T 3 NIL NIL)
(mac2 6 3 8) => (6 T 3 T (8))
编辑:关键字参数
上面显示的用法显然有缺陷。也许,这样更好:
(timeit (+ 1 1)) ; Vanilla call
(timeit :out-stream *standard-output* (+ 1 1)) ; Log the output to stdout
(timeit :out-stream *standard-output* :runs 1000 (+ 1 1)) ; Time over a 1000 iterations.
谢谢。
【问题讨论】:
-
但是你知道已经有一个宏可以做到这一点吗?
TIME. -
你写了一个函数?我看到的只是一个宏...
-
对不起,我是说宏。已更正。另外,我知道
TIME会这样做。这更适合练习编写宏。另外,我想包括一些时间没有的东西,比如迭代次数和日志记录等。 -
这意味着你不能写...
(timeit 1000 (+ 1 1))? -
是的,同意。我刚刚在你的回答下发表了评论。我认为可选的关键字参数可能更合适。我会努力实现的。
标签: lisp common-lisp sbcl