我试图将它减少到最小的例子。代码运行时没有错误,产生预期的输出。但它给了我一个警告,我的第一个变量是未定义的。似乎第二个预言陈述并没有“看到”第一个陈述的结果。谢谢你的帮助!
(我最初根本没有在代码中使用progn构造,但是在收到此错误之后我添加了它以查看是否会强制按顺序执行 - 但错误是相同的。)
以下是代码:
(let ((input (open "input.lisp")))
(progn (defvar var1 (read input))
(defvar arr1 (make-array var1 :initial-contents (read input))))
(close input))
(print var1)
(print arr1)
这些是文件“input.lisp”的内容:
9
(10 8 6 4 2 4 6 8 10)
这是我在执行后从sbcl获得的输出(加载“test.lisp”):
; in: DEFVAR ARR1
; (MAKE-ARRAY VAR1 :INITIAL-CONTENTS (READ INPUT))
;
; caught WARNING:
; undefined variable: VAR1
;
; compilation unit finished
; Undefined variable:
; VAR1
; caught 1 WARNING condition
9
#(10 8 6 4 2 4 6 8 10)
T
所以,在我看来,两个定义语句都在执行,但第二个定义语句没有“看到”第一个的结果。它仍然正确构造数组,因为它填充了给定的初始内容。但为什么var1还没有定义?
答案 0 :(得分:4)
请参阅Hyperspec中的documentation for defvar
:
如果
defvar
或defparameter
表单显示为顶级表单,则编译器必须识别该名称已被声明为special
。
这暗示(并且似乎是SBCL的情况)如果defvar
显示为非顶级形式,则编译器无需识别该名称已被声明。那你的defvar
怎么没有被编译为顶级表格呢?请参阅section 3.2.3.1, Processing of Top Level Forms(第6点)了解答案:代码周围的let
会将其编译为非顶级表单。
因此,您需要在顶层defvar
变量,然后在setf
内let
分配它们。
喜欢这个。使用with-open-file
而不是open
和close
通常也更简单。
(defvar var1)
(defvar arr1)
(with-open-file (input "input.lisp" :direction :input)
(setf var1 (read input))
(setf arr1 (make-array var1 :initial-contents (read input))))
(print var1)
(print arr1)
您遇到此问题的原因是您将代码放在文件的顶层。这是一个不太常见的事情:正常的Lisp编码风格是将大部分代码放在函数定义中,然后在需要运行它们时调用这些函数。
例如,这是编写此类代码的更典型方式,初始化代码在其自己的函数中。
(defvar *var1* nil "Documentation for var1.")
(defvar *arr1* nil "Documentation for arr1.")
(defun init-from-file (file)
"Read *var1* and *arr1* from file."
(with-open-file (input file :direction :input)
(setf *var1* (read input))
(setf *arr1* (make-array *var1* :initial-contents (read input)))))
(when (null *var1*) (init-from-file "input.lisp"))