Common Lisp中的动态非本地出口

时间:2018-06-09 03:07:25

标签: dynamic common-lisp exit

根据 Common Lisp the Language,2nd Edition Dynamic Non-Local Exits部分,

  

一旦启动控制权转移,就会放弃干预出口;在抛出的情况下,这发生在实施说明中提到的“第二次通过”的开始。尝试将控制权转移到动态范围已结束的出口是错误的。

然而,在SBCL 1.3.4中:

(catch 'a
  (catch 'b
    (unwind-protect
         (throw 'a "returning from protected")
      (throw 'b "returning from unwind"))))
;; => "returning from unwind"

这似乎不正确。在执行受保护和清理表单之间是否应该解除退出点'b,从而使上述非法?同一页上的划船示例表明了相同的情况。

SBCL的行为似乎与替代提案相对应:

  

...放弃退出应该与unwind-protect清理条款的评估以及动态绑定和捕获标记的撤消混在一起,以与建立相反的顺序执行所有操作。

这只是CLtL2与最终规格不同的问题吗?

1 个答案:

答案 0 :(得分:5)

正如jkiiski所解释的那样,ANSI Common Lisp中的行为未定义。这个例子在CLHS的UNWIND-PROTECT部分引用:

;;; The following has undefined consequences because the catch of B is 
;;; passed over by the first THROW, hence portable programs must assume 
;;; its dynamic extent is terminated.  The binding of the catch tag is not
;;; yet disestablished and therefore it is the target of the second throw.
 (catch 'a
   (catch 'b
     (unwind-protect (throw 'a 1)
       (throw 'b 2))))