根据 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与最终规格不同的问题吗?
答案 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))))