2

最小限の例に減らしてみました。コードはエラーなしで実行され、期待される出力が生成されます。しかし、最初の変数が未定義であるという警告が表示されます。progn の 2 番目のステートメントは、最初のステートメントの結果を「認識」していないようです。助けてくれてありがとう!

(私は元々、コードに 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 から取得した出力です (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

したがって、両方の定義ステートメントが実行されているように見えますが、2 番目のステートメントは最初のステートメントの結果を「認識」していません。指定された初期コンテンツで満たされているため、配列は正しく構築されます。しかし、なぜ var1 がまだ定義されていないのでしょうか?

4

1 に答える 1

4

Hyperspecのドキュメントをdefvar参照してください。

defvarordefparameterフォームがトップレベルのフォームとして表示される場合、コンパイラはその名前が宣言されていることを認識する必要がありspecialます。

defvarこれは、がトップレベル以外の形式として表示される場合、コンパイラが名前が宣言されていることを認識する必要がないことを意味します(SBCLの場合のようです) 。では、なぜあなたdefvarのはトップレベルのフォームとしてコンパイルされていないのですか?答えについては、セクション3.2.3.1、トップレベルフォームの処理(ポイント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"))
于 2011-07-03T20:26:22.647 に答える