3

私は余暇に Common Lisp を学んでいて、条件システムについて質問があります。

Common Lisp でエラーを処理するとき、ハンドラーで error-type を指定して、処理するエラーを決定します。エラーの発生と処理の間に、(restart-case などを使用して) いくつかの再起動を行うことができますが、restart でエラーの種類を指定することはできません。

たとえば、文字列とストリームを受け取り、文字列をストリームに送信し、ストリームからの応答を読み取って返す関数があるとします。メッセージが間違っている場合、ストリームからエラー応答を読み取ったとします。そして、エラーを発生させ、次のような新しいメッセージを要求する再起動をバインドしたい:

(defun process-message (stream raw-message)
  (let ((response (get-response stream raw-message)))
    (restart-case
        (when (response-error-p response)
          (error 'message-error :text response))
      (change-raw-message (msg)
        (process-message stream msg)))))

ここで、メッセージが複雑でsend-command、いくつかの引数からメッセージを作成してプロセス メッセージを呼び出すことができる別の関数を上位レベルで取得したとします。取得したrecreate-command-message場合、ユーザーが引数から新しいコマンドを送信できるようにする別の再起動をバインドしたいと思います。'message-errorこの再起動は、restart-case の の場所にある可能性がありますがprocess-message、完全に正しいとprocess-messageは言えません。このような高レベルの関数については知らずsend-command、戻り値が異なる可能性があるためです。

しかし、ストリームエラー (EOF など) がスローされrecreate-command-message、ソケットが失敗した場合、recreate-command-message再起動は超高レベルのsocket-errorハンドラーで利用可能になり、この再起動は役に立たず、慣用的に間違っています。

これはプログラム設計上の問題であり、そのような問題を回避するようにプログラムを設計する必要がありますか? それとも、再起動をエラー タイプにバインドする方法が見つからないか、条件システムを正しく理解していませんか?

ありがとう。

4

1 に答える 1

8

多分これは役立ちます:

(define-condition low-level-error (simple-error)
  ()
  (:report (lambda (c s)
             (format s "low level error."))))

(define-condition high-level-error (simple-error)
  ()
  (:report (lambda (c s)
             (format s "high level error."))))

(defun low-level (errorp)
  (restart-case
      (when errorp (error 'low-level-error))
    (go-on ()
      :report "go on from low-level"
      t)))

(defun high-level (high-level-error-p low-level-error-p)
  (restart-case
      (progn
        (when high-level-error-p (error 'high-level-error))
        (low-level low-level-error-p))
    (go-on ()
      :report "go on from high level"
      :test (lambda (c) (typep c 'high-level-error))
      t)))

引数にhigh-level異なる値(tまたは)を使用して呼び出してみて、それぞれの使用可能な再起動がニーズに合っているかどうかをデバッガーで確認してください。nil高レベルの再起動は、高レベルのエラーが通知された場合にのみ表示されます。高レベルの再起動はスタックに保持されるため、低レベルの機能は、回復するための高レベルの手段について知る必要はありません。

あなたの特定のユースケースについて、私があなたを正しく理解している場合、これは次のことを意味します。recreate-command-message再起動するための再起動を確立process-messagesend-command、高レベルのエラーに対してのみ使用できるようにします。

上記のリンクされたPCLの章Vsevolodを読んだ後でおそらくご存知のように、実際にこれらのエラーを処理すること、つまり、どの再起動を呼び出すかを決定することは、とで行われhandler-bindますhandler-case

于 2013-03-18T09:55:16.363 に答える