我是 Lisp 的新手,我想将时间的输出打印到文件(/tmp/foo.txt)中,所以我定义了一个关于时间的包装函数,如下所示:
(defun my-time(form)
(lisp::with-open-file (*trace-output* "/tmp/foo.txt"
:direction :output
:if-exists :append
:if-does-not-exist :create)
(time(form))))
(defun test(n)
(dotimes (i n) (format t "this is test ~a.~&" i)))
但是,当我运行(我的时间(测试 2))时,出现以下错误: 错误:使用参数 () 调用未定义的函数 FORM。
我做这个测试时没问题:(时间(测试2))
有人可以给我一些线索吗?
最佳答案
发生了什么
您的(test 2)
表单在my-time
运行之前执行,因为函数的参数始终在进入函数之前进行求值。因此,正如它所写的那样,它不会按您想要的方式工作。但仅此一点不会给您带来任何错误,只是测量不正确。
接下来,my-time
函数内部会发生什么:运行一个表单 form
。除非您事先定义了它,否则不存在这样的形式 - 因此您会收到错误。
每次 Lisp 遇到一个列表时,它都会尝试执行它。列表,其第一个元素是一个符号,表示名为 form 的函数或宏的名称。即使您使用引用,它也不会取消此规则:quote
表单将被执行并返回其内容作为结果。
(form element ...)
;^^^^ - from namespace for functions
Common Lisp 中有两个命名空间。具有可执行符号的命名空间和变量的命名空间。在 my-time
内部,您有变量 form
,但该符号位于变量的命名空间中,而不是函数的命名空间中。因此你会得到一个错误。
如何修复
有两种方法可以解决您的问题:
- 使用宏;
- 使用
lambda
封装您的表单,然后使用funcall
在my-time
内执行它。
涉及宏的解决方案
您可以使用与您的函数非常相似的宏:
(defmacro my-time(&body body)
`(with-open-file (*trace-output*
"/tmp/foo.txt"
:direction :output
:if-exists :append
:if-does-not-exist :create)
(time (progn ,@body))))
这会起作用(如果你足够幸运并且目录“temp”存在;-)
解决方案涉及函数
首先,定义我的时间
:
(defun my-time (form)
(with-open-file (*trace-output*
"/tmp/foo.txt"
:direction :output
:if-exists :append
:if-does-not-exist :create)
(time (funcall form))))
那我们来试试:
(my-time (lambda nil (time 2)))
有效。我的“foo.txt”文件现在充满了统计数据。
关于profiling - 如何在 Common Lisp 中定义宏时间的包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24467438/