例外を補足する


Tags: R6RS, 例外処理

例外が送出されると、例外ハンドラと呼ばれる 1 引数の手続きが例外の情報を表すオブジェクトを引数に呼び出される。

例外ハンドラは with-exception-handler 手続きで設定する。

補足した例外が raise により発生したものであり、例外ハンドラから処理が戻った場合には &non-continuable コンディションを含む例外が発生する。

(import (rnrs))

(with-exception-handler
    (lambda (exc)
      (display exc))
  (lambda ()
    (raise 1)))
;; -> 1
;; => &non-continuable

例外ハンドラは入れ子にすることができ、ハンドラ内で発生したコンディションは上位の例外ハンドラに引き渡される。

(import (rnrs))

(with-exception-handler
    (lambda (exc)
      (newline)
      (display exc))
  (lambda ()
    (with-exception-handler
        (lambda (exc)
          (display exc))
      (lambda ()
        (raise 1)))))
;; -> 1
;;    #<condition &non-continuable>
;; => &non-continuable

ハンドラ内で再度 raise してより上位の例外ハンドラに処理を委譲することもできる。

(import (rnrs))

(with-exception-handler
    (lambda (exc)
      (newline)
      (display (* exc 2)))
  (lambda ()
    (with-exception-handler
        (lambda (exc)
          (display exc)
          (raise exc))
      (lambda ()
        (raise 1)))))
;; -> 1
;;    2
;; => &non-continuable

また、別に例外補足用の構文として guard がある。

guard では補足した例外を変数に束縛し、 cond と同様の構文でその例外に対する条件分岐を行なうことができる。 guard によって設定された例外ハンドラで例外が処理された場合には、そのハンドラの戻した値が guard の値になる。

(import (rnrs))

(guard (con
        ((string? con)
         con)
        ((number? con)
         (number->string con))
        ((symbol? con)
         (symbol->string con)))
  (raise 'exception))
;; =>"exception"

どの条件節でも例外が処理されなかった場合には、その例外はさらに上位のハンドラに再度 raise される。

(import (rnrs))

(guard (con
        ((string? con)
         con)
        ((number? con)
         (number->string con))
        ((symbol? con)
         (symbol->string con)))
  (raise (make-error)))
;; => &error