Common lisp 公共口齿不清:为什么progn是一种特殊形式?

Common lisp 公共口齿不清:为什么progn是一种特殊形式?,common-lisp,Common Lisp,既然Common Lisp的函数参数按从左到右的顺序计算,为什么不使用普通函数: (defun progn2 (&rest body) (first (last body))) 不是特殊形式?返回它计算的最后一个形式的所有值,而是只返回第一个: (progn (values 1 2 3)) => 1, 2, 3 (progn2 (values 1 2 3)) => 1 progn(Rainer首先提到)的另一个关键特性是它保留了所有的形式,这使得宏可以扩展为多

既然Common Lisp的函数参数按从左到右的顺序计算,为什么不使用普通函数:

(defun progn2 (&rest body)
  (first (last body)))
不是特殊形式?

返回它计算的最后一个形式的所有值,而是只返回第一个:

(progn (values 1 2 3)) 
=>  1, 2, 3
(progn2 (values 1 2 3)) 
=>  1

progn
(Rainer首先提到)的另一个关键特性是它保留了所有的形式,这使得宏可以扩展为多种形式(例如,请参见我的答案)。

还有另一个用函数无法获得的
progn
特性:

(defun progn2 (&rest body)
  (first (last body)))
想象一下,在一个公共Lisp代码文件中有这样的代码:

(progn
  (defmacro foo () ))
vs

使用
PROGN
编译器会将
DEFMACRO
表单视为顶级表单。例如,这意味着编译器注意到存在宏定义,并使其在编译时环境中可用


使用函数
MY-PROGN
,编译器将无法识别
DEFMACRO
表单,因为它不在顶层。

是否
defun
已经包含隐式
PROGN
?检查
defun
的宏展开。@sds和@RainerJoswig的答案都很重要。@sds答案中的
可能会偶尔出现,而@RainerJoswig描述的行为非常重要,尤其是当您开始在源代码中放置基于宏的顶级表单时;如果这些生成的表单多于应被视为顶级的表单,那么您需要
progn
。顶级表单
的含义是什么?