我有以下 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))

你知道怎么做才能使它起作用吗?

谢谢,

纪尧勒

最佳答案

这与包无关。

使用 HANDLER-CASE,当处理程序运行时,堆栈已经展开。因此,函数中建立的重启消失了。

请改用 HANDLER-BIND。它在错误的上下文中运行处理程序,因此可以重新启动函数。

例子:

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

关于common-lisp - 通用列表 : Use handler-case in different packages,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31696970/

10-13 07:27