Различия в пакетах lisp между repl и файлом компиляции - PullRequest
2 голосов
/ 24 августа 2010

Сейчас я играю с 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 найден в repl, а не при компиляции файла?

1 Ответ

2 голосов
/ 25 августа 2010

Вся компиляция этого файла происходит перед выполнением любого из load-op s. Поэтому, когда 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-op s создадут пакет.


Так что вот немного больше информации о том, что здесь происходит:

  • Запись '#:some-name относится к символу, который не является частью какого-либо пакета. Таким образом, мы можем сделать ссылку на символическое имя без (1) предположения, что его пакет существует или (2) путаницы какого-то другого пакета с именем.
  • Затем '(symbol-name #:some-name) извлекает имя символа в виде строки. Почему бы просто не написать "some-name"? Вы могли бы, и это обычно будет работать. Но этот способ немного более надежен для случая запуска Lisp с учетом регистра в «современном режиме».
  • find-package отображает имя строки на представление пакета в Lisp. Помните, что к тому времени, когда вы запустите эту строку, ваш пакет будет существовать.
  • intern возвращает символ с указанным именем, который находится в данной упаковке.
  • symbol-function возвращает объект функции (лямбда-абстракцию или, скорее, ее скомпилированное представление), связанный с символом.
  • И затем funcall вызывает эту функцию. Это немного неуклюже, но, к сожалению, на самом деле нет лучшего способа смешать вызовы, которые загружают код, чтобы создать пакет с именами, содержащимися в этом пакете, в одном файле.
...