Ошибка «Нет MAKE-LOAD-FORM» с OpenMCL Common Lisp - PullRequest
7 голосов
/ 06 декабря 2008

Я пытаюсь запустить форму кода трассировки лучей ANSI Common Lisp Пола Грэма * на OS X, используя SLIME с OpenMCL (ну, теперь он называется CCL). В этом коде есть константа, значение которой является структурой, и когда я вызываю slime-compile-and-load-file или slime-compile-defun для любой функции, использует константу, я получаю сообщение об ошибке:

Метод MAKE-LOAD-FORM не определен для #S (ТОЧКА: X 0 : Y 0 : Z 200) [Состояние типа SIMPLE-ОШИБКА]

Я нашел пост , объясняющий усложнение, и другой , оплакивающий его, но что нужно добавить в код для согласования этого аспекта OpenMCL?

1 Ответ

8 голосов
/ 07 декабря 2008

Когда объекты STRUCTURE-OBJECT (и некоторые другие типы объектов) отображаются в виде литералов, константных объектов в коде, обрабатываемом COMPILE-FILE, COMPILE-FILE должен знать, как это устроить, когда загруженный результирующий двоичный файл загружает "эквивалентный" объект создан. Существует много возможных определений «эквивалента»: иногда важно, чтобы компоненты загруженного объекта разделяли структуру с другими объектами, иногда важно, чтобы инициализация происходила определенным образом, а иногда ничего из этого не важно. Чтобы определить, как воссоздать константный объект, COMPILE-FILE вызывает универсальную функцию MAKE-LOAD-FORM; это поведение должно быть описано в любом справочнике или учебнике по CL. (Ссылка или учебное пособие также должны учитывать, что реализация не может определять методы MAKE-LOAD-FORM по умолчанию, которые будут применимы ко всем экземплярам STRUCTURE-CLASS или STANDARD-CLASS, и также следует учитывать, что MAKE-LOAD-FORM-SAVING -SLOTS - это удобная функция для использования в методах MAKE-LOAD-FORM для объектов, инициализация которых не должна быть сложной, например:

(defmethod make-load-form ((p point) &optional env)
  (declare (ignore env))
  (make-load-form-saving-slots p))

Обратите внимание, что этот метод должен быть определен во время компиляции, чтобы COMPILE-FILE мог вызвать его, чтобы определить, как сохранить объект POINT с константой.

Ничто из этого не относится к CCL. Может возникнуть вопрос, какие вещи являются постоянными, буквальными объектами, а какие нет.

В коде типа:

(defconstant a-point (make-point :x 0 :y 0 :z 200))

(defun return-a-point () a-point)

компилятору разрешено (но не обязательно) подставлять значение A-POINT для ссылки на него в функции RETURN-A-POINT. (Если компилятор делает это, это означают, что в компилируемом коде есть объект POINT с литералом / константой, и COMPILE-FILE должен был бы вызвать MAKE-LOAD-FORM, чтобы определить, как объект должен быть сохранен и загружен; если компилятор не выполняет эту замену, то в этом примере вызывать MAKE-LOAD-FORM не нужно.)

Независимо от того, выполняет ли реализация такую ​​замену или нет, зависит от реализации. В спецификации также не указывается, оценивается ли форма значения в форме DEFCONSTANT во время компиляции, во время загрузки или в обоих случаях, и отмечает, что необходимо соблюдать осторожность (пользователем), чтобы выражение всегда вычислялось как то же значение.

CCL обычно пытается оценить форму значения DEFCONSTANT во время компиляции и довольно агрессивно заменяет значения именованных констант для ссылок на них; в некоторых случаях это означает, что методы MAKE-LOAD-FORM для классов значений констант должны быть определены. Другие реализации могут быть менее готовы сделать эту замену для некоторых типов объектов. Обе стратегии являются правильными, и переносимый код не может предположить, какие стратегии соблюдаются (хотя много якобы переносимого кода, безусловно, делает такие предположения.)

Различное обращение с вещами, определенными DEFCONSTANT, кажется наиболее вероятной причиной такого рода вещей (неожиданные вызовы MAKE-LOAD-FORM, которые никто не удосужился определить). Можно избежать некоторых из этих проблем способом, который должен быть переносимым, выполнив:

(defconstant a-point (make-point :x 0 :y 0 :z 200))

(defun return-a-point () (load-time-value (symbol-value 'a-point)))

Это будет иметь эффект, аналогичный простому разрешению реализации, которая хочет сделать это (как CCL), выполнять константу-подстановку, но использование LOAD-TIME-VALUE гарантирует, что константное значение будет оцениваться только при нагрузке время (и эта MAKE-LOAD-FORM не будет задействована.)

...