npt-japanese

% Macro HANDLER-CASE

UP


Macro HANDLER-CASE

Macro HANDLER-CASE

構文

handler-case expression [[{error-clause}* | no-error-clause]] => result*

clause::= error-clause | no-error-clause 
error-clause::= (typespec ([var]) declaration* form*) 
no-error-clause::= (:no-error lambda-list declaration* form*) 

引数と戻り値

expression - フォーム
typespec - 型指定子
var - 変数名
lambda-list - 通常のラムダリスト
declaration - 宣言式。評価されません。
form - フォーム
result - 通常の状況ではexpressionの評価による結果が返却されます。 例外的な状況では制御がclauseに遷移したときに、 clause内の最後のformの値が返却されます。

定義

handler-caseは 様々なハンドラーがアクティブになっている動的環境下で expressionを実行します。 各error-clauseは、 どのようなコンディションを捕捉するのか、 typespecでマッチされたものとして指定します。 no-error-clauseは、制御が通常の返却をしたときに 特定のアクションを指定することが許されます。

もしexpressionが実行中に error-clauseに適用できるコンディションが通知されたとき (例えば、(typep condition 'typespec)trueになるような 何らかのcondition)、 さらにその型のコンディションが介入できるハンドラーがないときは、 関係するerror-clauseの ボディ部に制御が遷移します。 このような場合、動的な状態を適切に巻き戻し、 (つまりexpression周りに確立されたハンドラーは もうアクティブではありません)、 varに通知されたコンディションを束縛します。 もし複数の場合が提供されたときは、 そのような場合は並列にアクセスされます。 例えば次のような場合、

(handler-case form
  (typespec1 (var1) form1)
  (typespec2 (var2) form2))

もし最初のclauseが(form1が含まれているもの)選ばれたとき、 2番目のハンドラーは見ることができません(そしてその反対も同様)。

clauseは上から下に順番に検索されます。 もしtypespec間で重複する型があるときは、 classeの早い方が選択されます。

もしvarが必要ないときは、それは省略できます。 つまりclauseは次のようなもの

(typespec (var) (declare (ignore var)) form)

これを(typespec () form)のように書くことができます。

もしformがないclauseが選択されたとき、 このような場合はhandler-casenilを返却します。 もしexpressionの実行が普通に返却され、 no-error-clauseがないときは、 handler-caseexpressionの結果が返却されます。 もしexpressionの実行が普通に返却され、 no-error-clauseがあるときは、 返却値はno-error-clauseから(lambda lambda-list form*)の 生成によって定義された関数の引数として使用され、 その関数の呼び出しの値がhandler-caseによる返却値になります。 この呼び出しの時点では、expression周りに確立されたハンドラーは もうアクティブではありません。

例文

(defun assess-condition (condition)
  (handler-case (signal condition)
    (warning () "Lots of smoke, but no fire.")
    ((or arithmetic-error control-error cell-error stream-error)
       (condition)
      (format nil "~S looks especially bad." condition))
    (serious-condition (condition)
      (format nil "~S looks serious." condition))
    (condition () "Hardly worth mentioning.")))
=>  ASSESS-CONDITION
(assess-condition (make-condition 'stream-error :stream *terminal-io*))
=>  "#<STREAM-ERROR 12352256> looks especially bad."
(define-condition random-condition (condition) () 
  (:report (lambda (condition stream)
             (declare (ignore condition))
             (princ "Yow" stream))))
=>  RANDOM-CONDITION
(assess-condition (make-condition 'random-condition))
=>  "Hardly worth mentioning."

影響

なし。

例外

なし。

参考

handler-bind, ignore-errors, 9.1. コンディションシステムの説明

備考

(handler-case form
  (type1 (var1) . body1)
  (type2 (var2) . body2) ...)

上記の式はおおよそ下記のものと同等です。

(block #1=#:g0001
  (let ((#2=#:g0002 nil))
    (tagbody
      (handler-bind ((type1 #'(lambda (temp)
                                      (setq #1# temp)
                                      (go #3=#:g0003)))
                     (type2 #'(lambda (temp)
                                      (setq #2# temp)
                                      (go #4=#:g0004))) ...)
      (return-from #1# form))
        #3# (return-from #1# (let ((var1 #2#)) . body1))
        #4# (return-from #1# (let ((var2 #2#)) . body2)) ...)))
(handler-case form
  (type1 (var1) . body1)
  ...
  (:no-error (varN-1 varN-2 ...) . bodyN))

上記の式はおおよそ下記のものと同等です。

(block #1=#:error-return
 (multiple-value-call #'(lambda (varN-1 varN-2 ...) . bodyN)
    (block #2=#:normal-return
      (return-from #1#
        (handler-case (return-from #2# form)
          (type1 (var1) . body1) ...)))))

TOP, Github