Common Lisp: как заставить (в пакете) работать из Emacs Slime

64-разрядная версия Windows 7
Clozure Common Lisp Version 1.9 WindowsX8632
Emacs 24.3.1
Slime changelog date 2014-06-17

У меня есть пример файла .lisp, который начинается следующим образом:

(ql:quickload 'qt)
(in-package "QT")

Остальная часть программы показывает диалоговое окно. Когда я запускаю это из командной строки, wx86cl -load helloqt.lisp кажется, что все работает нормально. Когда я запускаю это из Emacs Slime (C-x C-k), он говорит, что нет пакета «QT». Однако, если я сначала оценю первую строку отдельно (C-x C-e), тогда я смогу скомпилировать все это целиком, и оно заработает по модулю обычных проблем с попыткой запустить поток QT из Slime в Windows.

Как мне сделать так, чтобы я мог скомпилировать/запустить файл из emacs без необходимости сначала вручную оценивать первую строку?

Кроме того, почему (in-package ...) не меняет текущий пакет в сеансе Slime? Мне нужно изменить его вручную, если я хочу взаимодействовать с содержимым пакета.


person Sonicsmooth    schedule 23.11.2014    source источник
comment
На очень похожие вопросы уже были даны ответы. Это не будет в последний раз. Я добавил тег eval-when.   -  person Rainer Joswig    schedule 24.11.2014


Ответы (1)


Когда вы компилируете файл как единое целое, он сначала читается целиком. В то время ни один из них еще не был оценен, поэтому пакет QT еще не определен.

Вы можете либо использовать eval-when для оценки чего-либо в более раннее время, либо использовать средство определения системы (в настоящее время преобладает ASDF), чтобы загрузить вашу систему в правильном порядке.

Eval-when:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (ql:quickload '#:qt))

(in-package #:qt)

Обратите внимание, что обычно вам не следует копаться в пакетах библиотек, а нужно определить свой собственный свежий пакет для хранения вашего кода:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (ql:quickload '#:qt))

(defpackage #:qt-example
  (:use #:qt))

(in-package #:qt-example)

;; your code here

(Если вам интересно, defpackage, defun, defclass и т. д. — это специально разработанные макросы, которые разворачиваются в форму внутри такого eval-when.)

Иногда это нормально для небольших одноразовых сценариев. Для систем любого значимого размера, особенно если они имеют более одного исходного файла, используйте ASDF:

;;;; qt-example.asd

(in-package #:cl-user)

(asdf:defsystem #:qt-experiments
  :description "Some experiments with QT."
  :serial t
  :components ((:file "package")
               (:file "qt-example"))
  :depends-on (#:qt))

;;;; package.lisp

(defpackage #:qt-example
  (:use #:qt))

;;;; qt-example.lisp

(in-package #:qt-example)

ASDF поставляется с большинством реализаций Common Lisp с открытым исходным кодом. Возможно, вам потребуется настроить реестр ASDF. Мне нравится иметь один или два базовых каталога для всех моих локальных проектов, чтобы я мог просто поместить следующее в ~/.config/common-lisp/source-registry.conf:

(:source-registry
  (:tree (:home "devel"))
  (:tree (:home "src"))
  :inherit-configuration)

Затем ASDF находит все системы, определенные ниже этих каталогов. В SLIME вы можете просто использовать ,load-system или ,open-system из REPL с именем системы, чтобы загрузить его, соответственно. открыть в нем все файлы, при желании загрузив его.

При компиляции одной формы верхнего уровня (используя C-c C-c) из файла SLIME ищет оттуда форму in-package, чтобы узнать, какой пакет он должен принять. Обычно у вас должна быть только одна форма in-package для каждого файла вверху.

Обычно используемым ярлыком является C-c ~ в исходных файлах Lisp, который переключает REPL на каталог файла и эффективный пакет в данный момент.

person Svante    schedule 23.11.2014