Правильная загрузка файла для интерактивной разработки на Common Lisp

Я хотел бы знать, каков общий подход к интерактивной разработке на common-lisp в emacs (я использую sly, но я думаю, что инструкции по слизи должны быть такими же)

скажем, у меня есть этот файл:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (ql:quickload :closer-mop))

(in-package :cl-user)

(defpackage :shapes
  (:use :closer-common-lisp-user)
  (:export #:rectangle))

(in-package :shapes)

(defclass rectangle ()
  ((height :initform 0.0 :initarg :height)
   (width :initform 0.0 :initarg :width)))

что довольно просто. Оценка этого выражения по выражению, кажется, в порядке, а загрузка всего файла (C-c C-l) дает мне следующую ошибку:

The variable SHAPES:RECTANGLE is unbound.
   [Condition of type UNBOUND-VARIABLE]

раздевание его до

(in-package :cl-user)

(defpackage #:shapes
  (:use #:cl-user)
  (:export #:rectangle))

(in-package #:shapes)

(defclass rectangle ()
  ((height :initform 0.0 :initarg :height)
   (width :initform 0.0 :initarg :width)))

не вносит никаких изменений.

compile-and-load (C-c C-k) тоже не работает, оставляя меня с:

; in: DEFCLASS RECTANGLE
;     (SHAPES::DEFCLASS SHAPES:RECTANGLE NIL
;      ((SHAPES::HEIGHT :INITFORM 0.0 :INITARG :HEIGHT)
;       (SHAPES::WIDTH :INITFORM 0.0 :INITARG :WIDTH)))
; 
; caught COMMON-LISP:STYLE-WARNING:
;   undefined function: SHAPES::DEFCLASS

я вижу, что defclass нельзя правильно преобразовать в cl-user:defclass, но не вижу способа это исправить.

Интересно, что мне не хватает? И каков общий процесс интерактивной разработки в emacs?


person leetwinski    schedule 12.11.2020    source источник
comment
Пакет closer-common-lisp-user не экспортирует встроенные функции Lisp. Вам также нужно :use #'common-lisp.   -  person Barmar    schedule 12.11.2020
comment
может быть вместо этого есть пакет CLOSER-COMMON-LISP   -  person Rainer Joswig    schedule 12.11.2020
comment
Вот это да. Оба ваших ответа верны (неудивительно). Не могли бы вы переместить их в фактические ответы   -  person leetwinski    schedule 12.11.2020


Ответы (1)


Основная проблема здесь заключается в том, что вы путаете два способа использования пакетов в CL. Пакет обычно служит одной или обеим из двух целей:

  1. он может экспортировать ряд символов, предоставляя некий интерфейс к функциональности;
  2. это может быть пакет, в котором используются другие пакеты или из которого импортируются символы, но который не экспортирует никаких символов (если только он не является также пакетом типа 1).

Между этими типами пакетов нет формального различия, но очень часто существует неформальное различие. Пакеты второго типа часто называют *-USER, а каноническим примером является пакет CL-USER. Они часто (но не всегда) служат местами для набросков.

Итак, вы определяете пакет, список использования которого является таким пользовательским пакетом. Вы можете видеть, что это не сработает, просто взглянув на внешние символы этого пакета. Из вашего второго примера:

> (do-external-symbols (s (find-package "CL-USER"))
    (print s))
nil

Другими словами, CL-USER вообще не экспортирует символы. Это означает, что изначально у вашего пакета SHAPES вообще не будет доступа к каким-либо символам, и, в частности, ни один из символов CL не будет присутствовать.

Что ж, язык определяет канонический пакет «типа 1», то есть CL: вся цель этого пакета — экспортировать символы, определяющие язык Common Lisp, и только эти символы. Таким образом, определение пакетов SHAPES во втором примере должно быть

(defpackage #:shapes
  (:use #:cl)
  (:export #:rectangle))

(Обратите внимание, что SHAPES — это пакет типа 1: он предоставляет некоторую функциональность в форме SHAPES:RECTANGLE и, предположительно, предназначен для использования другими пакетами.)

Ближе к MOP доступны два пакета, которые отражают стандартные пакеты CL и CL-USER:

  • CLOSER-COMMON-LISP похож на CL, за исключением того, что различные символы заменены на символы, определенные Closer to MOP, и могут быть дополнительные символы MOP;
  • CLOSER-COMMON-LISP-USER похож на CL-USER: это пакет, предназначенный для общего использования, пользователи которого CLOSER-COMMON-LISP, но который вообще не экспортирует никаких символов.
person Community    schedule 13.11.2020
comment
Верно. Весь этот вопрос был основан на моем заблуждении, что пользовательские *-пользовательские пакеты реэкспортируют значения. Спасибо! - person leetwinski; 13.11.2020
comment
@leetwinski: да. Извините, если мой ответ был слишком длинным, поскольку я подозреваю, что вам не нужно ничего сложного: я хотел попробовать и оставить что-то, что может быть полезно в будущем. - person ; 13.11.2020