Next: , Previous: , Up: Nonlocal Exits   [Contents][Index]


11.7.2 catchthrowの例

2重にネストされたループから脱出する1つの方法は、catchthrowを使うことです(これはほとんどの言語ではgotoにより行なわれるだろう)。ここではijを0から9に変化させて、(foo i j)を計算します:

(defun search-foo ()
  (catch 'loop
    (let ((i 0))
      (while (< i 10)
        (let ((j 0))
          (while (< j 10)
            (if (foo i j)
                (throw 'loop (list i j)))
            (setq j (1+ j))))
        (setq i (1+ i))))))

fooが非nilをリターンしたら即座に処理を中止して、ijのリストをリターンしています。fooが常にnilをリターンする場合には、catchは通常どおりリターンして、その値はwhileの結果であるnilとなります。

以下では2つのリターン位置を一度に表す、微妙に異なるトリッキーな例を2つ示します。まず同じタグhackにたいして2つのリターン位置があります:

(defun catch2 (tag)
  (catch tag
    (throw 'hack 'yes)))
⇒ catch2

(catch 'hack
  (print (catch2 'hack))
  'no)
-| yes
⇒ no

どちらのリターン位置もthrowにマッチするタグをもつので内側のもの、つまりcatch2で確立されたcatchへgotoします。したがってcatch2は通常どおり値yesをリターンして、その値がプリントされます。最後に外側のcatchの2番目のbody、つまり'noが評価されて外側のcatchからそれがリターンされます。

ここでcatch2に与える引数を変更してみましょう:

(catch 'hack
  (print (catch2 'quux))
  'no)
⇒ yes

この場合も2つのリターン位置がありますが、今回は外側だけがタグhackで、内側はかわりにタグquuxをもちます。したがってthrowにより、外側のcatchが値yesをリターンします。関数printが呼び出されることはなくbodyのフォーム'noも決して評価されません。