次: , 前: Nonlocal Exits, 上: Nonlocal Exits


9.5.1 明示的な非ローカル脱出: catchthrow

ほとんどの制御構造は、その構造内での制御の流れだけに影響します。 関数throwは、通常のプログラム実行のこのような規則の例外です。 つまり、要求に従って非ローカルな脱出を行います。 (ほかにも例外はあるが、それらはエラー処理のためだけである。) throwcatchの内側で使い、 そのcatchへ戻ります。

     (defun foo-outer ()
       (catch 'foo
         (foo-inner)))
     
     (defun foo-inner ()
       ...
       (if x
           (throw 'foo t))
       ...)

フォームthrowを実行すると、対応するcatchへ制御が戻り、 そのcatchはただちに終了します。 throwに続くコードは実行されません。 throwの第2引数は、catchの戻り値として使われます。

関数throwは、その第1引数に基づいて対応するcatchを探します。 つまり、catchの第1引数が throwに指定されたものにeqであるcatchを探します。 そのようなcatchが複数個ある場合には、 もっとも内側のものを優先します。 したがって、上の例では、throwfooを指定し、 foo-outercatchは同じシンボルを指定しているので、 そのcatchを使います (ただし、これらのあいだには他の一致するcatchがないとして)。

throwの実行により、 対応するcatchまでのすべてのLispの構造を抜け出します。 これには関数呼び出しも含みます。 letや関数呼び出しなどの束縛を作る構造からもこのように抜け出すので、 通常どおり抜け出す場合と同様に束縛を解きます (see Local Variables)。 同様に、throwは、save-excursion(see Excursions)で 保存したバッファや位置情報、 save-restrictionで保存したナロイング状態、 save-window-excursion(see Window Configurations)で保存した ウィンドウの選択状態も復元します。 さらに、スペシャルフォームunwind-protectで設定した後始末を このフォームから抜け出すときに実行します(see Cleanups)。

throwは、テキスト上で、 ジャンプ先であるcatchの内側に現れる必要はありません。 throwは、catch内から呼ばれた別の関数からも戻ることもできます。 throwの実行が、 時間的にcatchに入ったあとで、かつ、それから抜けるまえである限り、 throwは対応するcatchを参照できます。 エディタコマンドループ(see Recursive Editing)から抜ける exit-recursive-editなどのコマンドで throwを使えるのは、このような理由からです。

Common Lispに関した注意: Common Lispを含むほとんどの他のLispには、 非逐次的に制御を移す方法がいくつかある。 たとえば、returnreturn-fromgo。 Emacs Lispにはthrowしかない。
— 特殊型: catch tag body...

catchは、関数throw向けに戻り位置を確立する。 その戻り位置は、tagによって他の戻り位置と区別される。 tagは、nil以外ならば任意のLispオブジェクトでよい。 引数tagは、戻り位置を確立するまえに、通常どおり評価される。

戻り位置を確立してから、catchは、bodyのフォームを テキスト上の順に評価する。 エラーや非ローカル脱出なしにフォームの実行が普通に終了した場合、 catchは、最後の本体フォームの値を返す。

bodyの内側で、tagと同じ値を指定したthrowが実行されると、 catchはただちに終了する。 このとき返す値は、throwの第2引数に指定されたものである。

— 機能: throw tag value

throwの目的は、 catchでまえもって確立しておいた戻り位置へ復帰することである。 引数tagは、さまざまな既存の戻り位置から選ぶために使う。 tagは、catchで指定した値とeqである必要がある。 tagに複数の戻り位置が一致する場合には、もっとも内側のものを使う。

引数valueは、対応するcatchの戻り値として使う。

タグtagである有効な戻り位置がなければ、 (tag value)を伴ったエラーno-catchを通知する。