为交互式 Common Lisp 开发正确加载文件

Properly load-file for interactive Common Lisp development

我想知道,在emacs中common-lisp交互开发的常用方法是什么(我用的是sly,但我认为slime指令应该是一样的)

假设我有这个文件:

(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)))

没有做任何改变。

编译并加载 (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 中交互开发的常见流程是什么?

这里的根本问题是您混淆了在 CL 中使用包的两种方式。一个包裹通常服务于两个目的之一,或同时服务于两个目的:

  1. 它可以导出一些符号,提供某种功能接口;
  2. 它可以是使用其他包或从中导入符号的包,但不导出任何符号(除非它也是类型 1 包)。

这些类型的包之间没有正式的区别,但通常有非正式的区别。上述第二种类型的包通常称为 *-USER,典型示例是 CL-USER 包。他们经常(但不总是)充当草稿工作的地方。

那么你所做的就是定义一个包,其使用列表就是这样一个用户包。您可以通过简单地查看此包的外部符号来了解这是行不通的。从你的第二个例子:

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

换句话说,CL-USER 导出根本没有符号。这意味着您的 SHAPES 包最初根本无法访问任何符号,特别是 none 的 CL 符号将出现。

好吧,该语言定义了一个规范的 'type 1' 包,即 CL:这个包的全部目的是导出定义 Common Lisp 语言的符号,并且仅导出那些符号。所以你的第二个例子中 SHAPES 包的定义应该是

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

(请注意,SHAPES 是类型 1 包:它以 SHAPES:RECTANGLE 的形式提供一些功能,因此可能旨在供其他包使用。)

Closer to MOP 提供了两个镜像标准 CLCL-USER 包的包:

  • CLOSER-COMMON-LISPCL一样,只是各种符号被Closer to MOP定义的替换了,可能还有额外的MOP符号;
  • CLOSER-COMMON-LISP-USER 类似于 CL-USER:它是一个用于一般用途的包,用户 CLOSER-COMMON-LISP 但根本不导出任何符号。