当前位置: 动力学知识库 > 问答 > 编程问答 >

common lisp - Statements not executing in order? (defvar within a let statement)

问题描述:

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?

网友答案:

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"))
分享给朋友:
您可能感兴趣的文章:
随机阅读: