2

我试图将其简化为最小的示例。代码运行没有错误,产生预期的输出。但它给了我一个警告,我的第一个变量是未定义的。似乎 progn 的第二个语句没有“看到”第一个语句的结果。谢谢您的帮助!

(我最初在代码中根本没有 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 还没有定义呢?

4

1 回答 1

4

请参阅Hyperspec 中的文档:defvar

如果 a defvarordefparameter表单作为顶级表单出现,编译器必须识别出该名称已被宣告special

这意味着(SBCL 似乎就是这种情况)如果 adefvar以非顶级形式出现,则编译器无需识别名称已被声明。那么为什么你defvar的 s 没有被编译为顶级表单呢?请参阅第 3.2.3.1 节,处理顶级表单(第 6 点)以获得答案:let您的代码周围会导致它被编译为非顶级表单。

因此,您需要defvar在顶层分配变量,然后稍后setflet.


像这样。with-open-file它通常也比openand更易于使用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"))
于 2011-07-03T20:26:22.647 回答