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))))
These are the contents of the file "input.lisp":
(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:
; caught 1 WARNING condition
#(10 8 6 4 2 4 6 8 10)
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:
defparameterform appears as a top level form, the compiler must recognize that the name has been proclaimed
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 220.127.116.11, 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
Like this. It's also usually simpler to use
with-open-file rather than
(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"))