4

私は次のlispコードを持っています:

;;; hop.lisp

(defpackage #:hop
  (:use #:cl ))

(in-package :hop)
(export 'hop)

(defun hop ()
  (restart-case
      (error "Hop")
    (hop ()
      (format t "hop"))))

常に失敗するが再起動を提供するダミー関数を定義する場所: hop.

別のパッケージでは、このファイルで:

;;; hip.lisp

(defpackage #:hip
  (:use #:cl #:hop))

(in-package :hip)

(defun dhip ()
  (hop:hop))

(defun hip ()
  (handler-case
      (hop:hop)
    (error (e)
      (declare (ignore e))
      (format t "restarts: ~a~%" (compute-restarts))
      (invoke-restart 'hop))))

最初のパッケージから関数 (hop) を呼び出す関数 (hip) と (dhip) を定義します。

(dhip) を呼び出すと、sbcl は、再起動ホップを使用して再起動することを選択できるプロンプトを表示します。

Hop
   [Condition of type SIMPLE-ERROR]

Restarts:
 0: [HOP] HOP
 1: [RETRY] Retry SLIME REPL evaluation request.
 2: [*ABORT] Return to SLIME's top level.
 3: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING     {1009868103}>)

Backtrace:
  0: (HOP)
  1: (DHIP)
  2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (DHIP) #<NULL-LEXENV>)
  3: (EVAL (DHIP))
--more--

これは私が期待したものです。

ただし、(hip) を呼び出すと、再起動ホップが (compute-restarts) によってリストされず、使用に失敗します:(

No restart HOP is active.
   [Condition of type SB-INT:SIMPLE-CONTROL-ERROR]

Restarts:
 0: [RETRY] Retry SLIME REPL evaluation request.
 1: [*ABORT] Return to SLIME's top level.
 2: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING    {1009868103}>)

Backtrace:
  0: (SB-INT:FIND-RESTART-OR-CONTROL-ERROR HOP NIL T)
  1: (INVOKE-RESTART HOP)
  2: ((FLET #:FUN1 :IN HIP) #<unused argument>)
  3: (HIP)
  4: (SB-INT:SIMPLE-EVAL-IN-LEXENV (HIP) #<NULL-LEXENV>)
  5: (EVAL (HIP))

これを機能させるために何ができるか知っていますか?

ありがとう、

ギヨール

4

1 に答える 1

5

これはパッケージとは関係ありません。

HANDLER-CASE を使用すると、ハンドラーが実行されるときに、スタックは既に巻き戻されています。したがって、関数で確立された再起動はなくなります。

代わりに HANDLER-BIND を使用してください。エラーのコンテキストでハンドラーを実行するため、関数の再起動が可能です。

例:

(defun hip ()
  (handler-bind ((error (lambda (e)
                          (declare (ignore e))
                          (format t "restarts: ~a~%" (compute-restarts))
                          (invoke-restart 'hop))))
      (hop)))
于 2015-07-29T10:00:33.960 に答える