Ошибка “Нет MAKE-LOAD-FORM” в OpenMCL Common Lisp
-
19-08-2019 - |
Вопрос
Я пытаюсь запустить код трассировки лучей от Пола Грэхема ANSI Common Lisp ( общий лисп ) в OS X используется SLIME с OpenMCL (ну, теперь называется CCL).В этом коде определена константа, значением которой является структура, и когда я вызываю либо slime-скомпилировать и загрузить файл или слизь-компиляция-удаление при любой функции, использующей константу, я получаю сообщение об ошибке:
Метод MAKE-LOAD-FORM не определен для #S(ТОЧКА: X 0 :Y 0 :Z 200) [Условие типа ПРОСТОЕ-ОШИБКА]
Я нашел сообщение объяснение сложности и еще один сожалею об этом, но что нужно добавить в код, чтобы согласовать этот аспект OpenMCL?
Решение
Когда СТРУКТУРНЫЕ объекты (и некоторые другие типы объектов) отображаются как литеральные, постоянные объекты в коде, обрабатываемом 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 мог вызвать его, чтобы определить, как сохранить объект constant POINT.
Ничто из этого не зависит от CCL.Что может быть, так это вопрос о том, какие вещи являются постоянными, буквальными объектами, а какие нет.
В коде, подобном:
(defconstant a-point (make-point :x 0 :y 0 :z 200))
(defun return-a-point () a-point)
компилятору разрешено (но не обязательно) заменять значение A-POINT ссылкой на него в функции RETURN-A-POINT.(Если компилятор сделает это, это будет означать, что в компилируемом коде есть объект literal / constant 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 задействован не будет).