将处理程序绑定与有状态闭包一起使用是否有效?
Is using handler-bind with a stateful closure valid?
这是一个符合标准的 Common Lisp 程序吗?
(handler-bind ((condition (let ((x 0))
(lambda (c)
(declare (ignore c))
(print (incf x))))))
(signal 'condition)
(signal 'condition))
SBCL (2.0.5.37) 的输出是:
1
1
ABCL/CCL/ECL 的输出是:
1
2
Common Lisp 标准定义了哪些行为?
结语
这是 SBCL 中的错误,it is now fixed。
不是很清楚。 spec 表示:
Executes forms in a dynamic environment where the indicated handler bindings are in effect.
然后说
If an appropriate type is found, the associated handler is run in a dynamic environment where none of these handler bindings are visible (to avoid recursive errors).
如果您将“运行”解释为调用函数,这表明在进行绑定时处理程序表达式被计算一次。这是 CCL/ABCL/ECL/LispWorks 实现,因此状态在闭包中保持。
但 SBCL 似乎已将“运行”解释为“评估和调用”的意思。因此每次处理程序 运行 和状态丢失时都会创建一个新的闭包。
我怀疑意图是第一种解释,因为 CL 没有其他“惰性”绑定。
如果将问题中的代码改成这样:
(let ((handler
(let ((x 0))
(lambda (c)
(declare (ignore c))
(print (incf x))))))
(handler-bind ((condition handler))
(signal 'condition)
(signal 'condition)))
那么 SBCL 的行为方式与其他实现方式相同。我认为这非常清楚地表明其他实现所采用的解释是预期的,并且它还提供了一个实际的解决方法,如果该解释实际上是正确的,那么它是 SBCL 中的一个错误。
这是一个符合标准的 Common Lisp 程序吗?
(handler-bind ((condition (let ((x 0))
(lambda (c)
(declare (ignore c))
(print (incf x))))))
(signal 'condition)
(signal 'condition))
SBCL (2.0.5.37) 的输出是:
1
1
ABCL/CCL/ECL 的输出是:
1
2
Common Lisp 标准定义了哪些行为?
结语
这是 SBCL 中的错误,it is now fixed。
不是很清楚。 spec 表示:
Executes forms in a dynamic environment where the indicated handler bindings are in effect.
然后说
If an appropriate type is found, the associated handler is run in a dynamic environment where none of these handler bindings are visible (to avoid recursive errors).
如果您将“运行”解释为调用函数,这表明在进行绑定时处理程序表达式被计算一次。这是 CCL/ABCL/ECL/LispWorks 实现,因此状态在闭包中保持。
但 SBCL 似乎已将“运行”解释为“评估和调用”的意思。因此每次处理程序 运行 和状态丢失时都会创建一个新的闭包。
我怀疑意图是第一种解释,因为 CL 没有其他“惰性”绑定。
如果将问题中的代码改成这样:
(let ((handler
(let ((x 0))
(lambda (c)
(declare (ignore c))
(print (incf x))))))
(handler-bind ((condition handler))
(signal 'condition)
(signal 'condition)))
那么 SBCL 的行为方式与其他实现方式相同。我认为这非常清楚地表明其他实现所采用的解释是预期的,并且它还提供了一个实际的解决方法,如果该解释实际上是正确的,那么它是 SBCL 中的一个错误。