正确地加载文件以进行交互式Common Lisp开发

问题描述

我想知道emacs中进行common-lisp交互式开发的常用方法是什么(我使用的是狡猾,但我认为粘液指示应该相同)

我有这个文件

(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类软件包)。

这两种类型的软件包之间没有形式上的区别,但是通常存在非正式的区别。上面第二种类型的软件包通常称为cv2,典型的例子是pip3 install opencv-python软件包。它们经常(但不总是)充当草稿工作的地方。

所以您要做的是定义一个软件包,其使用列表就是这样的用户软件包。您可以通过简单地查看此程序包的外部符号来看到这行不通。在第二个示例中:

*-USER

换句话说,CL-USER完全不输出符号。这意味着您的> (do-external-symbols (s (find-package "CL-USER")) (print s)) nil 包最初将根本无法访问任何符号,尤其是将出现个CL符号。

好吧,该语言定义了一个规范的'type 1'包,即CL-USER:该包的全部目的是导出定义Common Lisp语言的符号以及仅这些符号。因此,第二个示例中的SHAPES包的定义应为

CL

(请注意,SHAPES是类型1程序包:它以(defpackage #:shapes (:use #:cl) (:export #:rectangle)) 的形式提供了某些功能,因此可能打算供其他程序包使用。)

更接近MOP的版本提供了两个与标准SHAPESSHAPES:RECTANGLE软件包相同的软件包:

  • CLCL-USER相似,只是各种符号被“更接近MOP”定义的符号代替,并且可能还有其他MOP符号;
  • CLOSER-COMMON-LISP类似于CL:这是供一般使用的软件包,CLOSER-COMMON-LISP-USER用户可以使用,但根本不会导出任何符号。