语句不按顺序执行? (let 语句中的 defvar)

发布于 2024-11-18 01:37:22 字数 883 浏览 3 评论 0原文

我试图将其减少到最小的示例。代码运行没有错误,产生预期的输出。但它警告我,我的第一个变量未定义。看来 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 还没有定义呢?

I've tried to reduce it to the minimal example. The code runs without an error, producing the expected output. But it gives me a warning that my first variable is undefined. It seems that the second statement of progn doesn't "see" the results of the first statement. Thanks for the help!

(I originally did not have the progn construct in the code at all, but after getting this error I added it to see if that would force execution in order -- but the error is the same.)

Here's the code:

(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)

These are the contents of the file "input.lisp":

9
(10 8 6 4 2 4 6 8 10)

And this is the output I get from sbcl after executing (load "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

So, it seems to me that both definition statements are executing, but the second doesn't "see" the results of the first. It still constructs the array correctly because it's filled with the given initial-contents. But why isn't var1 already defined?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

半世晨晓 2024-11-25 01:37:22

请参阅 Hyperspec 中的 defvar 文档 :

如果 defvardefparameter 形式作为顶级形式出现,编译器必须识别出该名称已被声明为special。< /p>

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

因此,您需要在顶层 defvar 变量,然后稍后在 let 中使用 setf 分配它们。


像这样。使用 with-open-file< 通常也更简单/a> 而不是打开关闭

(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"))

See the documentation for defvar in the Hyperspec:

If a defvar or defparameter form appears as a top level form, the compiler must recognize that the name has been proclaimed special.

This implies (and it seems to be the case for SBCL) that if a defvar appears as a non-top-level form, then the compiler need not recognize that the name has been declared. So how come your defvars are not being compiled as top level forms? See section 3.2.3.1, Processing of Top Level Forms (point 6) for the answer: the let surrounding your code causes it to be compiled as non-top-level forms.

So you need to defvar your variables at top level, and then assign them later on with setf inside the let.


Like this. It's also usually simpler to use with-open-file rather than open and 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)

The reason that you are having this trouble is that you are placing your code at top level in the file. This is a slightly unusual thing to do: the normal Lisp coding style is to put most of your code in function definitions, and then to call those functions when you need to run them.

For example, this would be a more typical way to write this kind of code, with the initialization code in its own function.

(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"))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文