如何在Common Lisp中定义宏时间的包装器

时间:2014-06-28 13:45:59

标签: profiling common-lisp

我是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))时,会出现以下错误: 错误:使用arguments()调用未定义的函数FORM。

我做这个测试时没关系:(时间(测试2))

有人可以给我一些线索吗?

1 个答案:

答案 0 :(得分:5)

发生了什么

您的(test 2)表单在my-time运行之前正在执行,因为函数的参数在进入函数之前始终会被评估。因此,在编写时,它将无法正常工作。但仅凭这一点并没有给你任何错误,只是错误的测量。

接下来,my-time函数内部会发生什么:您运行表单form。除非你事先定义了它,否则没有这样的形式 - 所以你得到一个错误。

每次Lisp遇到一个列表时,它都会尝试执行它。 List,其中第一个元素是表示名为 form 的函数或宏的名称的符号。即使您使用引号也不会取消此规则:quote表单将被执行并返回其内容。

(form element ...)
;^^^^ - from namespace for functions

Common Lisp中有两个名称空间。带有可执行符号和变量名称空间的命名空间。在my-time内部,您有变量form,但此符号位于变量的名称空间中,而不是函数。因此,您会收到错误。

如何修复

有两种方法可以解决您的问题:

  • 使用宏;
  • 使用lambda包裹您的表单,然后使用my-timefuncall内执行。

涉及宏的解决方案

您可以使用与您的功能非常相似的宏:

(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”存在; - )

涉及功能的解决方案

首先,定义my-time

(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”文件现在已经充满了统计数据。