Нет ошибки MAKE-LOAD-FORM с OpenMCL Common Lisp

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

Метод MAKE-LOAD-FORM не определен для #S(POINT :X 0 :Y 0 :Z 200) [Условие типа SIMPLE-ERROR]

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


person Brendan Foote    schedule 06.12.2008    source источник


Ответы (1)


Когда STRUCTURE-OBJECTs (и некоторые другие типы объектов) появляются как литеральные константные объекты в коде, обрабатываемом 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 не будет задействован.)

person Community    schedule 07.12.2008
comment
Я полагаю, вы имели в виду вызов RETURN-A-POINT в форме DEFCONSTANT? - person Elias Mårtenson; 11.08.2012