различия в пакетах lisp между repl и compile file

Сейчас я играю с lispbuilder-sdl на SBCL под Windows.

Мой исходный код выглядит следующим образом:

(asdf:operate 'asdf:load-op :lispbuilder-sdl)
(asdf:operate 'asdf:load-op :lispbuilder-sdl-binaries)
(asdf:operate 'asdf:load-op :lispbuilder-sdl-examples)
(sdl-examples:squashed)

Когда я компилирую файл, я получаю сообщение об ошибке: пакет "SDL-EXAMPLES" не найден.

Если я удалю (sdl-examples: squashed) из файла, он скомпилируется нормально. Затем я могу ввести (sdl-examples: squashed) в ответ, и демонстрационная игра начнется нормально.

Почему пакет sdl-examples обнаружен в ответе, но не при компиляции файла?


person Giles Roberts    schedule 24.08.2010    source источник


Ответы (1)


Вся компиляция этого файла происходит перед выполнением любого из load-ops. Итак, когда Lisp компилирует строку (sdl-examples:squashed), он не запускает load-op, который определяет ваш пакет.

Вы можете обойти это, не упоминая пакет sdl-examples, который требует от читателя найти его символ squashed перед фактическим выполнением load-op:

(funcall (symbol-function (intern (symbol-name '#:squashed)
                                  (find-package (symbol-name '#:sdl-examples)))))

Идея состоит в том, чтобы вычислить пакет по его символическому имени, найти символ, называющий вашу функцию, и получить функцию, которую он называет, - но этот способ требует, чтобы пакет существовал только при запуске кода, а не при его первом чтении. Затем все ваши четыре оператора могут быть скомпилированы, выполнены по порядку, и к моменту выполнения этого последнего оператора ваш load-ops создаст пакет.


Итак, вот еще немного информации о том, что здесь происходит:

  • Запись '#:some-name относится к символу, который не является частью какого-либо пакета. Таким образом, мы можем сделать ссылку на символическое имя без (1) предположения, что его пакет существует, или (2) без использования какого-либо другого пакета с этим именем.
  • Затем '(symbol-name #:some-name) извлекает имя символа в виде строки. Почему бы просто не написать "some-name"? Вы могли бы, и это обычно срабатывает. Но этот способ немного более надежен для случая запуска Лиспа, чувствительного к регистру в "современном режиме".
  • find-package отображает имя строки в представление пакета в Лиспе. Помните, что к тому времени, как вы запустите эту строку, ваш пакет будет существовать.
  • intern возвращает символ с заданным именем, который находится в данном пакете.
  • symbol-function возвращает объект функции (лямбда-абстракцию или, что более вероятно, ее скомпилированное представление), связанный с символом.
  • И затем funcall вызывает эту функцию. Это немного неуклюже, но, к сожалению, лучшего способа смешать вызовы, которые загружают код, для создания пакета с именами, живущими в этом пакете, в том же файле, на самом деле нет.
person JohnMaraist    schedule 25.08.2010
comment
Спасибо за ответ. Это несколько выходит за рамки моего понимания шепелявости. Я молодой кузнечик, которому нужен воск на воске. Когда я запускаю это, функция-символ говорит, что требуется только один аргумент. Как связать объект пакета со строкой символов? Я предполагаю, что это не так. - person Giles Roberts; 25.08.2010
comment
Ой! Моя беда - забыл о вызове intern, чтобы склеить имя функции и пакет вместе. Сейчас он отредактирован, чтобы исправить. - person JohnMaraist; 26.08.2010
comment
Большое спасибо за объяснение. Это помогло мне понять, что такое символы и разница во времени компиляции и выполнения. Я предполагаю, что если бы я начал программировать реальное приложение, этой неприятности можно было бы избежать, определив код в отдельном файле asd? - person Giles Roberts; 26.08.2010
comment
@Giles Roberts: Да, я бы порекомендовал именно это. Когда вы затем загружаете (или компилируете) свой пакет, ASDF гарантирует, что системы, от которых вы зависите, загружены (и, если необходимо, скомпилированы). - person Vatine; 26.08.2010
comment
Спасибо. На минуту мне показалось, что у меня смешные глаза, но это просто ТАК неправильно синтаксис, выделяющий код lisp. - person Giles Roberts; 26.08.2010