#こんにちは
#他の言語でいう例外処理をやりたいのですが、unwind-protect が try-finally に相当するものだとすると try-catch-finally に相当することを書くにはどうするのがいいんでしょうか。
#クラスの内部状態を一時的に変更するんだけど、例外が起きたときは元に戻して例外はそのまま上に上げたいのです。例外が起きなければ変更したままでいいのでunwind-protectのcleanup-formのとこに書くとなんかしっくりこないのですが、どう書くものなんでしょう
#例外が起きたときだけ何かするなら handler-case ですかねー。
#> 例外はそのまま上に上げたい
#が例外を値として返すのではなく、例外の通知として上に伝えたいなら handler-bind が必要なケースかも。
#ありがとうございます。やっぱりそうなっちゃうんですか。でもCLに用意されてないとすると自分はなにか標準的な書き方をはずれたことをやろうとしてるのかな、と。
#例外、正確にはコンディションでしたね、それは値として補足せずそのままコンディションとして呼出のネストの上に上げたいです。handler-bindのformにはどう書けばいいのでしょう。
#実践CommonLispを見ていたのですが、invoke-restartでリスタートしたいわけじゃなく、またコンディションの型自体にも興味がなく、単にコンディション通知が上がる前のフック的にクラスの内部状態を元に戻したいですが、いったいどう書くのだろうかと悩んでます。
#handler-bind のハンドラにコンディションが引っかかったときに、ハンドラから invoke-restart とかで制御を移さなければそのままコンディションが(さらに上に)上がっていく感じです。
#(handler-bind
((error (lambda (err)
;; 例外の後始末
...)))
;; 本来の処理
...)
#はう。インデントが変なことに。
#あー、ごめんなさい。上のなしで。
#(unwind-protect
(handler-bind
((error (lambda (err)
;; 元に戻す(A)
...)))
;; クラスの内部状態を一時的に変更して何かする
...)
;; 元に戻す(B)
..)
#おお。そうなんですね。handler-bindの仕様は読んだつもりでしたが理解できていませんでした。bind-formで制御の流れを変えなければ単にコンディションは上に上がっていくんですね。コンディションすべてをbind-formでとらえるにはすべてのスーパークラスであるところのTでいいんでしょうか。
#あ、お、、、(何
#うーむ。
#さっそく試してみます。
#どうもありがとう。
#先にさっきのコードの説明。 (B) のところで元に戻せば、正常/異常問わず抜けるときには内部状態は元に戻る。
#例外発生時には、(A) のところで元に戻してからコンディションが上に伝わっていって、上位のハンドラなりデバッガなりで処理される。処理された後に unwind-protect から抜けるので、(B) でもっかい元に戻そうとしてしまう。
#あと、例外発生時に (A) で一時的な変更を元に戻した後上位のハンドラとかデバッガからリスタートすると、一時的な変更が元に戻されたままになってるので注意が必要かも。
#説明ヘタクソですみません。
#> コンディションすべてをbind-formでとらえるには
#t とか condition (全てのコンディションの親玉)で全部拾えはするんですけど
#warning とかは投げられたのを放っといても処理とまらなくて、それを拾ってクラスの状態元に戻して、そのまま続行される。ってなると面倒な事になるのではないか。という気がしました。
#warningというコンディションもあるんですね
#warn関数がwarning型のコンディションをシグナルするみたいですね。handler-bindのbind-form部にcondition型を指定してみたところ確かに補足できました。というか補足したくないシチュエーションですね。指摘ありがとうございます。
#condition型の階層にはsimple-condition, serious-condition, warningがあるみたいです。simple-condition, serious-condition をhandler-bindすればいいんだろうか。serious-conditionの説明がよく理解できないのですが、デバッガに入ることはないってどういう意味でしょう。 これなんですが http://www.lispworks.com/documentation/HyperSpec/Body/e_seriou.htm #warningと同様って事かな。とすると serious-conditionのサブクラスのerrorを使うべきなのか。あ...つまりhandler-bindでerror型を補足すれば十分という事なのか。もしかして。
#CL の condition が通知されたときにデバッガに落ちるかどうかは、投げられた condition の型ではなくて投げるのに使った関数(error だとデバッガ行き、signar or warn だとそのまま続行)なんですよね。
#なので、handler-bind や handler-case で「デバッガに入るようなコンディションが通知されたら」というのは、正確にはできないです。
#ちょっと記憶頼りですけど CLHS とかでも serious-condition (error 含む) を投げるときは error、warning なら warn、それ以外なら signal で通知するように、という事になってて、わざわざ serious-condition とか error を signal で投げることは無いと思うんで、handler-bind で serious-condition を捕まえておく、でいいのではないかと。
#なるほどー。興味深いです。