表題

プログラムの例外処理

著者

Richard Kelsey, Michael Sperber

状態

この SRFI は現在「確定」の状態である。 SRFI の各状態の説明については ここ を参照せよ。 この SRFI は 2002-10-20 までは、あるいは、修正が終わるまでは、 草案の状態にあるだろう。 この SRFI の議論に投稿するには、 srfi minus 34 at srfi dot schemers dot org にメールを送信してください。 このメーリングリストに参加する方法については ここの説明 を参照せよ。 この SRFI に関する議論については メーリングリストのアーカイブ を参照せよ。 この SRFI に関する確定後の議論については メーリングリストのアーカイブ を参照せよ。

概要

この SRFI では、Scheme のための例外処理と例外のレイズについて定義する。

この SRFI は William Clinger, R. Kent Dybvig, Matthew Flatt, Marc Feeley により提案された (そして廃止された) 「SRFI 12: 例外処理」 をベースにしている。

論拠

この SRFI で提案する例外メカニズムの目標は、 プログラマが例外処理を用いたコードを共有することを促進し、 既存の Scheme システムに容易に追加できることである。

この SRFI は他の SRFI とともに使用するときに有用である:

仕様

例外ハンドラは1つの引数を受け取る手続きであり、 例外的な状況が発生したときのプログラムの動作を決定する。 システムは暗黙的にカレントの例外ハンドラを管理する。

プログラムはカレントの例外ハンドラを起動し、 例外に関する情報をカプセル化したオブジェクトを渡すことで、 例外をレイズする。 1つの引数を受け取る任意の手続きは、例外ハンドラとして使用することができ、 任意のオブジェクトは、例外を表現するために使用することができる。

システムはカレントの例外ハンドラをプログラムの動的環境の一部として管理する。 カレントの入力ポートや出力ポート、dynamic-wind コンテキストと似ている。 この動的環境は、戻り値の場所を指定しない継続であると考えることができる。 この動的環境には、入力ポート、出力ポート、dynamic-wind コンテキスト、 および、この SRFI で定めるカレントの例外ハンドラが含まれる。 current-dynamic-environment および with-dynamic-environment の移植性のある定義については、参照実装を参照せよ。

プログラムの初期状態におけるカレント例外ハンドラは、実装依存である。 しかし、それはプログラムを abort したり、デバッガを起動したり、 あるいは、他の何らかの振る舞いをするだろうから、 ユーザーに見える形の影響を与えることになるだろう。

例外ハンドラの構築

(with-exception-handler handler thunk)

thunk の評価結果を返す。 handler は1つの引数を受け取る手続きである。 この手続きが thunk 呼び出しの動的エクステントに カレント例外ハンドラとして設定される。

(guard ( <var> <clause1 > <clause2 > ...) <body>) (syntax)

構文: 各 <clause> は cond の clause と同じ形式を持つこと。

意味: guard フォームを評価すると、例外ハンドラを設定した上で <body> を評価する。 例外ハンドラは、レイズされたオブジェクトを <var> に束縛し、 cond 式と同じ方法で caluse を評価する。 guard 式の継続と動的環境の中で、 暗黙の cond 式が評価される。 もし、全ての <clause> の <test> を評価した結果が false であり、 else 節が存在しない場合、 元の raise 呼び出しの動的環境の中で、 例外オブジェクトが再度レイズされる。 ただし、このときのカレント例外ハンドラは、 guard を囲む動的環境の例外ハンドラになる。

例外のレイズ

(raise obj)

obj に対してカレントの例外ハンドラを起動する。 このハンドラは、raise 呼び出し時の動的環境の中で呼び出される。 ただし、その動的環境のカレント例外ハンドラは、 その例外ハンドラを設定した with-exception-handler 呼び出し時の動的環境の例外ハンドラになる。 with-exception-handler が呼び出されていない場合の 例外ハンドラの継続は未定義である。

使用例

(call-with-current-continuation
 (lambda (k)
   (with-exception-handler (lambda (x)
                             (display "condition: ")
                             (write x)
                             (newline)
                             (k 'exception))
     (lambda ()
       (+ 1 (raise 'an-error))))))
PRINTS: condition: an-error
=> exception

(call-with-current-continuation
 (lambda (k)
   (with-exception-handler (lambda (x)
                             (display "something went wrong")
                             (newline)
                             'dont-care)
     (lambda ()
       (+ 1 (raise 'an-error))))))
PRINTS: something went wrong
then behaves in an unspecified way

(guard (condition
         (else
          (display "condition: ")
          (write condition)
          (newline)
          'exception))
  (+ 1 (raise 'an-error)))
PRINTS: condition: an-error
=> exception

(guard (condition
         (else
          (display "something went wrong")
          (newline)
          'dont-care))
 (+ 1 (raise 'an-error)))
PRINTS: something went wrong
=> dont-care

(call-with-current-continuation
 (lambda (k)
   (with-exception-handler (lambda (x)
                             (display "reraised ") (write x) (newline)
                             (k 'zero))
     (lambda ()
       (guard (condition
                ((positive? condition) 'positive)
                ((negative? condition) 'negative))
        (raise 1))))))
=> positive

(call-with-current-continuation
 (lambda (k)
   (with-exception-handler (lambda (x)
                             (display "reraised ") (write x) (newline)
                             (k 'zero))
     (lambda ()
       (guard (condition
                ((positive? condition) 'positive)
                ((negative? condition) 'negative))
        (raise -1))))))
=> negative

(call-with-current-continuation
 (lambda (k)
   (with-exception-handler (lambda (x)
                             (display "reraised ") (write x) (newline)
                             (k 'zero))
     (lambda ()
       (guard (condition
                ((positive? condition) 'positive)
                ((negative? condition) 'negative))
        (raise 0))))))
PRINTS: reraised 0
=> zero

(guard (condition
         ((assq 'a condition) => cdr)
         ((assq 'b condition)))
  (raise (list (cons 'a 42))))
=> 42

(guard (condition
         ((assq 'a condition) => cdr)
         ((assq 'b condition)))
  (raise (list (cons 'b 23))))
=> (b . 23)

参照実装

この参照実装は「SRFI 9: レコード型の定義」 と 「SRFI 23: エラー報告機構」 を利用している。

(define *current-exception-handlers*
  (list (lambda (condition)
          (error "unhandled exception" condition))))

(define (with-exception-handler handler thunk)
  (with-exception-handlers (cons handler *current-exception-handlers*)
                           thunk))

(define (with-exception-handlers new-handlers thunk)
  (let ((previous-handlers *current-exception-handlers*))
    (dynamic-wind
      (lambda ()
        (set! *current-exception-handlers* new-handlers))
      thunk
      (lambda ()
        (set! *current-exception-handlers* previous-handlers)))))

(define (raise obj)
  (let ((handlers *current-exception-handlers*))
    (with-exception-handlers (cdr handlers)
      (lambda ()
        ((car handlers) obj)
        (error "handler returned"
               (car handlers)
               obj)))))

(define-syntax guard
  (syntax-rules ()
    ((guard (var clause ...) e1 e2 ...)
     ((call-with-current-continuation
       (lambda (guard-k)
         (with-exception-handler
          (lambda (condition)
            ((call-with-current-continuation
               (lambda (handler-k)
                 (guard-k
                  (lambda ()
                    (let ((var condition))      ; clauses may SET! var
                      (guard-aux (handler-k (lambda ()
                                              (raise condition)))
                                 clause ...))))))))
          (lambda ()
            (call-with-values
             (lambda () e1 e2 ...)
             (lambda args
               (guard-k (lambda ()
                          (apply values args)))))))))))))

(define-syntax guard-aux
  (syntax-rules (else =>)
    ((guard-aux reraise (else result1 result2 ...))
     (begin result1 result2 ...))
    ((guard-aux reraise (test => result))
     (let ((temp test))
       (if temp
           (result temp)
           reraise)))
    ((guard-aux reraise (test => result) clause1 clause2 ...)
     (let ((temp test))
       (if temp
           (result temp)
           (guard-aux reraise clause1 clause2 ...))))
    ((guard-aux reraise (test))
     test)
    ((guard-aux reraise (test) clause1 clause2 ...)
     (let ((temp test))
       (if temp
           temp
           (guard-aux reraise clause1 clause2 ...))))
    ((guard-aux reraise (test result1 result2 ...))
     (if test
         (begin result1 result2 ...)
         reraise))
    ((guard-aux reraise (test result1 result2 ...) clause1 clause2 ...)
     (if test
         (begin result1 result2 ...)
         (guard-aux reraise clause1 clause2 ...)))))

参考文献

著作権

Copyright (C) Richard Kelsey, Michael Sperber (2002). All Rights Reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


編集者: Francisco Solsona