2011/04/09

error って。



error という関数がある。ヘルプで見てみる。


出た。「例外」だ。なんとなくしか分かってない。うそです。まったく分かっていない(w


試してみる。たとえば、



(defvar a 0)

(defun test ()
(interactive)
(error "!!!") ; ここで抜けてる
(incf a))

;; test
(test) ; 何回呼んでも
a ; a はゼロのまま
0


とかして、何回 test を呼ぼうが (incf a) は実行されないので、a はいつまでたってもゼロのままになる。


じゃあ error ってのはただ脱出するだけなのか。C言語の break や return なのか。ちょっとそれは違うようだ。


handler-case というのを使えば、(error なんちゃら) として発行したエラーを捕まえてそのときのエラー処理ができるようだ。


そんなことをしてなにが面白いのか。


ココが参考になる。例外の仕組みのない C言語と lisp の比較がおもしろい。


例をやってみる。



; 例 1
(handler-case (/ 10 0))

0で除算しました: /: (10 0) ; エラーを補足できてないので、最終的に xyzzy が受け取った


; 例 2
(handler-case (/ 10 0)
(division-by-zero (c) c)) ; division-by-zero 型のエラーを補足して、そのエラーを返す

#S(division-by-zero operation / operands (10 0)) ; これがエラーの中身


ここで、例 2 の形を詳しく見てみる。


f:id:gnrr:20110410024528p:image:w400


例 2 のエラー処理は 単に c となってて、これは、引数 c で捕まえたエラーを単に返すよっていうエラー処理だ。


ややこしいのは、通常処理補足するエラーの種類(型)が同じ error という名前になったとき。



; 例 3
(handler-case (error "~D番のエラーが起きました" 2)
(error (c) c)) ; error 型のエラーを補足して、そのエラーを返す

#S(simple-error format-string "~D番のエラーが起きました" format-arguments (2))


これは、




  1. 通常処理で error 関数を使ってエラーを発行しといて、

  2. それを error という型で捕まえている


関数名も例外の型の名前も、同じ error という名前だからややこしい。


で、上の例 3 には問題があって、この通常処理の (error "文字列") の書式だと 発行するエラーの種類が simple-error というエラー型に固定されてしまう。


じゃあ、例 2 みたいにもっと細かい種類のエラーを発行したいときはどうするかというと、



(handler-case (error (make-condition 'division-by-zero
(error (c) c))
#S(division-by-zero operation / operands (10 0)) ; 例 2 と同じエラーの型にできた


というふうに、文字列ではなくて make-condition で作ってやる必要がある。


今日はここまでにしとこうか。




そういえば昔、 C言語から C++ に移ろうとしたときに例外処理はうまく理解できなくて、使いこなせなかった。でも人のコードではバリバリ使われてて、そのうち C++ のコードを読むのがしんどくなった。


その後 delphi をやり出したけど、やっぱり例外処理を理解してなくて、ただ定型的に書いていた。


まったく恥ずかしい限り。


経験的にいうと、昔解けなかった問題はその後何度も出題されて、そのつど僕を困らせる。逃げても追いかけてくる。


でも、逃げる以外の方法がある。理解することだ。


今回は逃げずに例外と向き合ってみようと思う。





Related Posts Plugin for WordPress, Blogger...

0 コメント :

コメントを投稿