为交互式 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 包)。
这些类型的包之间没有正式的区别,但通常有非正式的区别。上述第二种类型的包通常称为 *-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 提供了两个镜像标准 CL
和 CL-USER
包的包:
CLOSER-COMMON-LISP
和CL
一样,只是各种符号被Closer to MOP定义的替换了,可能还有额外的MOP符号;
CLOSER-COMMON-LISP-USER
类似于 CL-USER
:它是一个用于一般用途的包,用户 CLOSER-COMMON-LISP
但根本不导出任何符号。
我想知道,在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 包)。
这些类型的包之间没有正式的区别,但通常有非正式的区别。上述第二种类型的包通常称为 *-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 提供了两个镜像标准 CL
和 CL-USER
包的包:
CLOSER-COMMON-LISP
和CL
一样,只是各种符号被Closer to MOP定义的替换了,可能还有额外的MOP符号;CLOSER-COMMON-LISP-USER
类似于CL-USER
:它是一个用于一般用途的包,用户CLOSER-COMMON-LISP
但根本不导出任何符号。