Common lisp:prog2 的 return 值是多少?

Common lisp: what is the return value of prog2?

人们会期望 prog2 不同于 prog1progn 在 return 评估 第二个 的结果表达式分别代替 firstlast。 然而,HyperSpec 说了一些不同的东西(强调我的):

prog2 evaluates first-form, then second-form, and then forms, yielding as its only value the primary value yielded by first-form.

这意味着 prog2 会 return 与 prog1 一样(并且实际上表现得很好)!

有趣的是,HyperSpec 中的示例证实了 预期的 而不是 指定的 行为:

(setq temp 1) =>  1
(prog2 (incf temp) (incf temp) (incf temp)) =>  3
temp =>  4
(prog2 1 (values 2 3 4) 5) =>  2

这是标准中的错字还是我漏掉了更深层次的东西?

这似乎是 known issue with the ANSI standard (the full list can be found on CLiki).

我已经用 SBCL 2.0.1 和最新版本的 Allegro 对其进行了测试,在这两种情况下它的行为都符合预期(而不是指定的):

CL-USER> (prog2
             (print "1st")
             (print "2nd")
           (print "3rd"))

"1st" 
"2nd" 
"3rd" 
"2nd"

想想看,连缩进都这么暗示。

感兴趣的话,我可以将以下代码输入到 Portacle (Emacs / SLIME / SBCL) 中:

(prog2
   (print "1st")
   (print "2nd")
   (print "3rd"))

我将光标放在 prog2 上,并使用了键序列 M-.。这显示了 SBCL 实际在做什么。

(sb-xc:defmacro prog2 (form1 result &body body)
  `(prog1 (progn ,form1 ,result) ,@body))

所以 SBCL 是对提供的表格进行模式匹配。第一个参数是形式form1,第二个参数是形式result,其他的都是body。函数 progn returns 在评估 form1 时形式 result 的值,并且 prog1 在评估 body.[=22 时也会选择该值=]

结论 - 它正在做明智的事情,而不是 Hyperspec 所说的。