Ger*_*ton 1 lisp calendar common-lisp astronomy
我曾经用 Cadence Design Systems 的衍生品 Skill 编写小型 Lisp 程序和中型程序。我现在想使用日历计算附带的 Lisp 函数“库” ,可以从剑桥大学下载(供个人使用)。
我在 Windows 10 计算机上安装了 Lipstick 软件包(我以前没有使用过)。(至少我用过Emacs)。我一直在使用Peter Seibel 的Practical Common Lisp (2005) 作为文本。
我想首先在 REPL 中进行单独的函数调用,因此我想在 REPL 中“安装”“库”。我将这些词放在引号中是因为我不确定使用正确的 Lisp 词。我尝试加载文件但失败了,所以我尝试了
(compile-file "calendar.l")
Run Code Online (Sandbox Code Playgroud)
REPL 缓冲区中的响应是
; compiling file "c:/Users/card9/lispstick/calendar.l" (written 19 JUN 2022 01:12:02 PM):
; compiling (IN-PACKAGE "CC4")
Run Code Online (Sandbox Code Playgroud)
另一个缓冲区 sldb[2] 中的响应是
The name "CC4" does not designate any package.
[Condition of type SB-Kernel:SIMPLE-PACKAGE-ERROR]The name "CC4" does not designate any package.
[Condition of type SB-Kernel:SIMPLE-PACKAGE-ERROR]
Run Code Online (Sandbox Code Playgroud)
所以我的问题是我应该对包含所有日历函数的 Lisp 文件进行哪些更改,以便我可以编译和加载它,或者,我应该使用什么其他方法来访问这些函数?
ign*_*ens 10
这是非常古老的代码并且写得不好。如果您使用比 SBCL 更宽松的编译器,您可能更有机会让它轻松工作:我可以在 LispWorks 和 Clozure CL 中编译并加载它,但当我试图让 SBCL 编译它时,我最终失去了生存的意愿。
请参阅下文,了解可能适用于 SBCL 的建议解决方法。
这些是您将遇到的第一件事,并且此答案的第一个版本仅处理此问题。这段代码似乎依赖于in-package
20 世纪 80 年代(具体来说,似乎是1989 年)消失的语义!
正确的解决方法(也许更简单的方法请参见下文)是更改
(in-package "CC4")
...
(export ...)
Run Code Online (Sandbox Code Playgroud)
类似的东西
(defpackage "CC4"
(:use "CL")
(:export ...))
(in-package "CC4")
Run Code Online (Sandbox Code Playgroud)
导出的名称应转换为字符串(包含大写名称的字符串),或者可能更简单的未驻留符号(名称前缀为#:
,因此在表单中(export ... 'foo ...)
转换为)。(:export ... #:foo ...)
defpackage
一个更简单的修复方法需要对代码进行较小的编辑,因此可能更可取,即在表单之前放置(in-package "CC4")
以下内容:
(defpackage "CC4"
(:use "CL"))
Run Code Online (Sandbox Code Playgroud)
另一个修复方法是预定义包,从而避免编辑文件:请参见下文。
完成此操作后,您应该至少有机会编译该文件。如果有效(可能还有其他问题),那么您可以加载它,然后需要说
(use-package "CC4")
Run Code Online (Sandbox Code Playgroud)
defconstant
问题,第一部分有很多地方defconstant
使用 ,其中常量的值取决于其他函数,第一个是
(defconstant jd-epoch
;; TYPE moment
;; Fixed time of start of the julian day number.
(rd -1721424.5L0))
Run Code Online (Sandbox Code Playgroud)
但是用 定义的东西的值defconstant
需要在编译时知道:
如果
defconstant
表单显示为顶级表单,则编译器必须识别该名称命名为常量变量。实现可以选择在编译时、加载时或两者都评估值形式。因此,用户必须确保可以在编译时评估初始值(无论文件中是否出现对名称的引用),并且它始终评估为相同的值。
而编译文件时却不是这样。
解决此问题的方法是将调用的用于计算任何形式的值的函数包装defconstant
在合适的 中eval-when
,因此
(defun rd (tee)
...)
Run Code Online (Sandbox Code Playgroud)
会成为
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun rd (tee)
...))
Run Code Online (Sandbox Code Playgroud)
这看起来不错,但你会得到这样的结果:
(defconstant icelandic-epoch
;; TYPE fixed-date
;; Fixed date of start of the Icelandic calendar.
(fixed-from-gregorian (gregorian-date 1 april 19)))
Run Code Online (Sandbox Code Playgroud)
现在 和fixed-from-gregorian
需要gregorian-date
像eval-when
它们调用或引用的任何东西一样被包裹起来。
那么,除了跟踪代码以查找需要包装的所有函数之外,还有两种解决此问题的方法。
第一个是将defconstant
s 更改为defparameter
s 并希望代码中没有任何内容尝试分配或以其他方式破坏变量。这会降低性能,但这可能并不重要。
另一种是做传统的事情,像这样的可怕系统在 CL 的史前时期经常需要:在尝试编译系统之前,加载它解释的。这是一个小包装文件,它将尝试执行此操作,并且还预定义了包:
;;;;; Try to compile & load calendar.l
;;;
(in-package :cl-user)
;;; Define the package to avoid doom
;;;
(defpackage "CC4"
(:use "CL"))
(let ((source (merge-pathnames (pathname "calendar.l") *load-truename*)))
;; Load the source, compile it and load that.
(load source)
(load (compile-file source)))
Run Code Online (Sandbox Code Playgroud)
defconstant
第二部分:订单如果你看一下代码,你会发现第 1596 行有一个fixed-from-icelandic
使用summer
free 的定义。 summer
在第 4142 行被定义为常量。因此,这意味着基本上没有办法compile-file
可以完成像样的编译工作fixed-from-icelandic
:在编译之前需要知道自由变量是常量。
不过,这也可以通过加载首先解释的文件来解决。
defconstant
第三部分:最终的崩溃这就是我放弃SBCL的地方。SBCL 对 有着非常严格的解释defconstant
,我认为基于上面引用的规范条款。这意味着像这样的事情
(defconstant foo '(1 2))
Run Code Online (Sandbox Code Playgroud)
在SBCL中基本上是不可能的。该链接后面描述了解决方法。
嗯,这意味着实际上没有机会用 SBCL 编译这段代码,因为这样的情况很多,而且在加载解释版本后编译它的机会更小,而这是我们需要做的。
其他 CL 实现对此不太严格,并且会很高兴。
或许可以让 SBCL 编译此代码的某些衍生版本,但需要对其进行重大修改。即使不那么挑剔的编译器也会发出许多合理的警告。
然而我强烈怀疑这段代码从未被编译过。因此,一种解决方法是根本不尝试编译该文件:将加载器填充程序修改为:
;;;;; Try to load calendar.l
;;;
(in-package :cl-user)
;;; Define the package to avoid doom
;;;
(defpackage "CC4"
(:use "CL"))
;;; Don't even try to compile the file
(load (merge-pathnames (pathname "calendar.l") *load-truename*))
Run Code Online (Sandbox Code Playgroud)
这样做甚至可以让 SBCL 加载该文件。SBCL 在编译各个定义时会发出大量警告,因为它是仅由编译器实现的。
最终的结果是否会起作用是另一个问题,但它会加载。
首先这是一件特别不幸的事情:大多数 CL 代码并不像这样糟糕。