11

为了完全理解如此强大的 lisp 宏,我想到了一个问题。我知道关于宏的一条黄金法则是“当函数完成工作时,切勿使用宏”。然而,阅读第 9 章 -实用:构建单元测试框架- 从《实用的通用 Lisp

;; Function defintion. 

(defun report-result (result form)
  (format t "~:[FAIL~;pass~] ... ~a~%" result form))

;; Macro Definition

(defmacro check (form)
  `(report-result ,form ',form))

好的,我理解它的目的,但我可以使用函数而不是宏来完成它,例如:

(setf unevaluated.form '(= 2 (+ 2 3)))

(defun my-func (unevaluated.form)
  (report-result (eval unevaluated.form) unevaluated.form))
  1. 这是否可能只是因为给定的宏太简单了?
  2. 此外,由于代码本身(如控制结构、函数等)被表示为 LIST,Lisp 宏系统相对于它的对手来说是否如此强大?
4

3 回答 3

14

但如果它是一个宏,你可以这样做:

(check (= 2 (+ 2 3)))

使用函数,您必须执行以下操作:

(check '(= 2 (+ 2 3)))

此外,宏(= 2 (+ 2 3))实际上是由编译器编译的,而函数是由 eval 函数评估的,不一定是同一件事。

附加物:

是的,它只是评估功能。现在这意味着什么取决于实现。有些人可以解释它,有些人可以编译和执行它。但简单的事情是你不知道从一个系统到另一个系统。

其他人提到的空词汇环境也很重要。

考虑:

(defun add3f (form)
  (eval `(+ 3 ,form)))

(demacro add3m (form)
  `(+ 3 ,form))

然后观察:

[28]> (add3m (+ 2 3))
8
[29]> (add3f '(+ 2 3))
8
[30]> (let ((x 2)) (add3m (+ x 3)))
8
[31]> (let ((x 2)) (add3f '(+ x 3)))

*** - EVAL: variable X has no value
The following restarts are available:
USE-VALUE      :R1      Input a value to be used instead of X.
STORE-VALUE    :R2      Input a new value for X.
ABORT          :R3      Abort main loop
Break 1 [32]> :a

对于大多数用例来说,这真的很糟糕。由于 eval 没有词法环境,它无法x从封闭的. 中“看到” let

于 2012-07-21T20:28:58.700 回答
4

更好的替换是 not with eval,它不会在所有情况下都按预期执行(例如,它无法访问词法环境),而且也是矫枉过正(见这里:https ://stackoverflow.com/ a/2571549/977052),但是使用匿名函数的东西,像这样:

(defun check (fn)
  (report-result (funcall fn) (function-body fn)))

CL-USER> (check (lambda () (= 2 (+ 2 3))))

顺便说一句,这就是在 Ruby 中完成这些事情的方式(procs那里调用匿名函数)。

但是,正如您所看到的,它变得不那么优雅了(除非您添加语法糖),而且实际上还有一个更大的问题:function-bodyLisp 中没有函数(尽管可能有非标准的方法来实现它)。总体而言,如您所见,对于这项特定任务,替代解决方案要差得多,尽管在某些情况下这种方法可能会奏效。

但是,一般来说,如果您想对传递给宏的表达式的源代码做一些事情(通常这是使用宏的主要原因),函数是不够的。

于 2012-07-21T20:28:28.853 回答
3

report-result函数需要源代码和执行结果。

该宏CHECK从单一来源形式提供两者。

如果你将一堆check表单放入文件中,它们很容易使用编译 Lisp 文件的通常过程进行编译。您将获得检查代码的编译版本。

使用函数和EVAL(更好地使用COMPILE)您会将源评估推迟到以后。它是否被解释或编译也不清楚。在编译的情况下,您稍后会得到编译器的检查。

于 2012-07-22T02:25:31.830 回答