反復とは、プログラムの一部を繰り返し実行することを指します。例えば、リストの各要素に対して、あるいは0からnまでの各整数に対して、ある計算を1回ずつ繰り返したい場合があるでしょう。Emacs
Lispでは、特殊フォームwhileを用いてこれを行うことができます:
while はまず condition
を評価する。その結果が nil 以外であれば、テキスト順に forms を評価する。次に condition
を再評価し、その結果が nil 以外であれば、再び forms を評価する。この処理は、condition が nil と評価されるまで繰り返される。
実行される反復回数に制限はありません。ループは、condition が nil と評価されるか、あるいはエラーや throw
によってループが抜けるまで継続します(非局所的な終了を参照)。
while フォームの値は常に nil です。
(setq num 0)
⇒ 0
(while (< num 4)
(princ (format "Iteration %d." num))
(setq num (1+ num)))
⊣ Iteration 0.
⊣ Iteration 1.
⊣ Iteration 2.
⊣ Iteration 3.
⇒ nil
各反復で処理を実行し、その後に終了判定を行う repeat-until ループを記述するには、ここに示すように、本体に続いて終了判定を記述したものを
progn とし、それを while
の第1引数として渡します:
(while (progn
(forward-line 1)
(not (looking-at "^$"))))
これは1行分進み、空行に到達するまで行単位で移動し続けます。whileに本体がなく、終端判定(これが実際にポイントを移動させる役割も担っています)のみがあるという点で独特です。
dolist と dotimes
マクロを使えば、よくある2種類のループを便利に記述できます。
この構文は、list の各要素に対して body
を1回ずつ実行し、変数 var をローカルにバインドして現在の要素を保持します。その後、result を評価した値、あるいは result
が省略されている場合は nil の値を返します。例えば、dolist を使用して reverse
関数を定義する方法は以下の通りです。
(defun reverse (list)
(let (value)
(dolist (elt list value)
(setq value (cons elt value)))))
この構文は、0(含む)からcount(除く)までの各整数に対してbodyを1回ずつ実行し、現在の反復における整数に変数varをバインドします。その後、resultを評価した値、あるいはresultが省略されている場合はnilを返します。resultの使用は非推奨です。以下に、dotimesを使用して何かを100回行う例を示します。
(dotimes (i 100) (insert "I will not obey absurd orders\n"))