Macros: Standard Control Constructs(宏:标准控制结构)
尽管起源于Lisp 的许多编程思想(从条件表达式到垃圾收集)都已经被吸取进其他语言,但 Lisp 的宏系统却始终使它保持了在语言风格上的独特性。不幸的是,宏这个字虽然在计算领域可以描述很多东西,但和 Common Lisp的宏相比,它们仅具有模糊和大致的相似性。当 Lisp 程序员们试图向非 Lisp 程序员解释宏这种特性的伟大之处时,这种相似性导致了无休止的误解。要想理解 Lisp 的宏,就真的需要重新看待它,不能带有任何基于其他碰巧叫做宏的概念所带来的成见。现在先退一步,从观察各种语言支持扩展的不同方式讨论 Lisp 宏。
All programmers should be used to the idea that the definition of a language can include a standard library of functionality that’s implemented in terms of the “core” language—functionality that could have been implemented by any programmer on top of the language if it hadn’t been defined as part of the standard library. C’s standard library, for instance, can be implemented almost entirely in portable C. Similarly, most of the ever-growing set of classes and interfaces that ship with Java’s standard Java Development Kit (JDK) are written in “pure” Java.
One advantage of defining languages in terms of a core plus a standard library is it makes them easier to understand and implement. But the real benefit is in terms of expressiveness—since much of what you think of as “the language” is really just a library—the language is easy to extend. If C doesn’t have a function to do some thing or another that you need, you can write that function, and now you have a slightly richer version of C. Similarly, in a language such as Java or Smalltalk where almost all the interesting parts of the “language” are defined in terms of classes, by defining new classes you extend the language, making it more suited for writing programs to do whatever it is you’re trying to do.
使用核心加上标准库的方式来定义语言的优势在于易于理解和实现。但真正的好处在于其可表达性——由于所认为的 “该语言” 很大程度上其实是一个库,因此很容易对其进行扩展。如果 C 语言中不含有所需的用来做某件事的一个函数,那就可以写出这个函数,然后就得到了一个特性稍微丰富一点的 C 版本。类似地,在诸如 Java 或 Smalltalk 这类几乎全部的有趣部分都是由类来定义的语言里,通过定义新的类就可以扩展该语言,使其更适用于编写你正试图编写的无论什么程序。
尽管 Common Lisp 支持所有这些扩展语言的方法,宏还提供了另一种方式。如同第 4 章所概述的那样,每个宏都定义了自己的语法,它们能够决定那些被传递的 S-表达式如何被转换成 Lisp 形式。核心语言有了宏,就有可能构造出新的语法——诸如 WHEN、DOLIST 和 LOOP 这样的控制构造以及 DEFUN 和 DEFPARAMETER 这样的定义形式,从而作为 “标准库” 的一部分而不是将其硬编码到语言核心。这已经牵涉到语言本身是如何实现的,但作为一个 Lisp 程序员你更关心的将是它所提供的另一种语言扩展式,使这些新语法可以使 Common Lisp 成为更好的用于表达特定编程问题解决方案的语言。
Now, it may seem that the benefits of having another way to extend the language would be easy to recognize. But for some reason a lot of folks who haven’t actually used Lisp macros—folks who think nothing of spending their days creating new functional abstractions or defining hierarchies of classes to solve their programming problems—get spooked by the idea of being able to define new syntactic abstractions. The most common cause of macrophobia seems to be bad experiences with other “macro” systems. Simple fear of the unknown no doubt plays a role, too. To avoid triggering any macrophobic reactions, I’ll ease into the subject by discussing several of the standard control-construct macros defined by Common Lisp. These are some of the things that, if Lisp didn’t have macros, would have to be built into the language core. When you use them, you don’t have to care that they’re implemented as macros, but they provide a good example of some of the things you can do with macros. In the next chapter, I’ll show you how you can define your own macros.