Shammer's Philosophy

My private adversaria

do-loop の終了判定タイミング

do でループさせる処理を書いていて、思った通りの箇所でループを抜けずにいろいろ試してみた。どうやら、ループ内で使用する変数の初期化処理があると、それを行うまで判定処理が実行されないらしい。時系列で整理すると、

  1. do 内で使用する変数の初期化
  2. 終了判定
  3. メインの処理
  4. 最初に戻る

という流れのようだ。なので、仮に

  1. do 内で使用する変数の初期化
  2. メインの処理
  3. 終了判定

というようにしたい場合は、変数の初期化をメインの処理に含める必要がある。具体的には、

(do ((x (init-x-value) (init-x-value))
         (y (init-y-value) (init-y-value)))
        ((finish-judgement-function))
    (format t "~A~A~%" x y))

という書き方ではなく以下のようにする。

(do ()
        ((finish-judgement-function))
    (let ((x (init-x-value))
              (y (init-y-value)))
        (format t "~A~A~%" x y)))

先の書き方だと、format 直後に finish-judgement-function が実行されず、function 直後には x と y の初期化が行われ、初期化後に finish-judgement-function が実行される。後者のようにすると、format 直後に finish-judgement-function が実行され、C言語の do { } while () のような状態になる。