Допустимо ли использование привязки обработчика с закрытием с сохранением состояния?

#lisp #common-lisp #sbcl #ccl #condition-system

#lisp #common-lisp #sbcl #ccl #условие-система

Вопрос:

Соответствует ли это программе 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, теперь она исправлена.

Комментарии:

1. Я только что попробовал SBCL 1.2.11, я получил второй результат.

2. Я нахожусь на Mac, SBCL 2.x, похоже, недоступен.

3. Mac SBCL 2.1.1 выдает первое.

Ответ №1:

Это не совсем понятно. В спецификации говорится:

Выполняет формы в динамической среде, где действуют указанные привязки обработчика.

а затем говорит

Если найден подходящий тип, связанный обработчик запускается в динамической среде, где ни одна из этих привязок обработчика не видна (чтобы избежать рекурсивных ошибок).

Если вы интерпретируете «выполнить» как вызов функции, это предполагает, что выражения обработчика вычисляются один раз, когда выполняются привязки. Это реализация CCL / ABCL / ECL / LispWorks, поэтому состояние сохраняется при закрытии.

Но SBCL, похоже, интерпретировал «run» как означающий «вычисляется и вызывается». Таким образом, при каждом запуске обработчика создается новое закрытие, и состояние теряется.

Я подозреваю, что целью была первая интерпретация, поскольку CL не имеет других «ленивых» привязок.

Если вы измените код в вопросе на этот:

 (let ((handler
        (let ((x 0))
          (lambda (c)
            (declare (ignore c))
            (print (incf x))))))
  (handler-bind ((condition handler))
    (signal 'condition)
    (signal 'condition)))
 

тогда SBCL ведет себя так же, как и другие реализации. Я думаю, это достаточно ясно показывает, что интерпретация, принятая другими реализациями, является предполагаемой, а также предоставляет практическое решение для того, что, если эта интерпретация на самом деле верна, является ошибкой в SBCL.

Комментарии:

1. конечно, поскольку он предоставил решение.

2. @coredump: я думаю, что ответ Бармара правильный. Я бы даже не понял проблему, если бы он не ответил ( handler-bind это то, что я всегда должен помнить, как это работает). Было бы нормально, если бы я объединил свой обходной путь с его ответом с помощью редактирования, а затем вы приняли это объединенное решение?

3. Да, пожалуйста, это было бы здорово

4. @coredump: ХОРОШО, я сделал это, если вы довольны изменением и хотите принять этот комбинированный ответ, который был бы отличным: тогда я уничтожу свой, поскольку не думаю, что это служит какой-либо цели.

5. @tfb К вашему сведению, теперь это исправлено в SBCL ( github.com/sbcl/sbcl/commit /… )