宏的目的

宏用于生成代码,转换代码和提供新的符号。这些新的符号可以更适合于更好地表达程序,例如通过提供域级构造或全新的嵌入式语言。

宏可以使源代码更加不言自明,但调试可能会变得更加困难。根据经验,当常规函数执行时,不应该使用宏。当你使用它们时,避免常见的陷阱,尝试坚持常用的模式和命名约定。

宏扩展订单

与函数相比,宏以相反的顺序扩展; 最重要的是,最后一次。这意味着默认情况下,不能使用内部宏来生成外部宏所需的语法。

评估订单

有时宏需要移动用户提供的表单。必须确保不要改变它们的评估顺序。用户可能依赖于按顺序发生的副作用。

仅评估一次

宏的扩展通常需要多次使用同一个用户提供的表单的值。表格可能会产生副作用,或者可能会调用昂贵的功能。因此宏必须确保只评估一次这样的形式。通常,这将通过将值赋给局部变量(其名称为 GENSYMed)来完成。

宏使用的函数,使用 EVAL-WHEN

复杂的宏通常在不同的函数中实现其逻辑的一部分。但是,必须记住,在编译实际代码之前会扩展宏。编译文件时,默认情况下,在宏执行期间,同一文件中定义的函数和变量将不可用。宏使用的同一文件中的所有函数和变量定义必须包含在 EVAL-WHEN -form 中EVAL-WHEN 应该指定所有三次,当在加载和运行时期间也应该评估所附的代码。

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defun foobar () ...))

这不适用于从宏的扩展调用的函数,只适用于宏本身调用的函数。