常见的Lisp异常处理(条件和重新启动)

use*_*063 5 exception restart common-lisp conditional-statements condition-system

我已经阅读了几天时间的通用Lisp“ Practical Common Lisp”异常处理一章,但是现在我对示例和解释感到困惑,与此同时,我尝试编写一些测试示例,但是由于我不起作用意料之中,以下是我的测试样本。

  1. 条件定义

    (define-condition evenp-error (error) 
      ((text :initarg :text :reader text)))
    
    Run Code Online (Sandbox Code Playgroud)
  2. 定义打印奇数的函数

    (defun filter-evenp (lst)
      (dolist (x lst)
        (if (not (evenp x)) 
          (print x)
          (error 'evenp-error :text x))))
    
    Run Code Online (Sandbox Code Playgroud)
  3. 重启功能

    (defun skip-evenp (c) (invoke-start 'skip-evenp))
    
    Run Code Online (Sandbox Code Playgroud)
  4. 重新启动案例

    (restart-case (filter-evenp (list 1 2 3 4 5))
      (skip-evenp () nil))
    
    Run Code Online (Sandbox Code Playgroud)

我要做的就是打印所有奇数并跳过偶数错误,我的样本出了什么问题?有人帮忙吗?提前谢谢了!!

cor*_*ump 6

实用Common Lisp相当详细,但条件系统可能需要一些时间才能习惯。您可能对Kent Pitman的文章感兴趣:Lisp的异常情况Lisp语言家族中的条件处理

什么是条件系统中提到了这些,为什么要一个?。也有许多其他参考,例如此Wikibooks条目或C2 Wiki的CommonLispConditionSystem条目。

定义重启

一个RESTART-CASE基本上说:

我将执行此表单,我不在乎它是否表示条件。但是,如果确实如此,并且您想从这种情况中恢复过来,则可以采用以下几种方法来解决该问题(重试,忽略等)。

通常,您无法说出如何从调用点被调用的代码中的错误中恢复。换句话说,filter-evenp应该restart-case按顺序包装代码以提供替代路径。对于您的示例,只需使用CERROR,就足以在建立CONTINUE重新启动时发出错误信号。

(if (evenp x)
  (cerror "Ignore even number" 'evenp-error :text x) 
  (print x))
Run Code Online (Sandbox Code Playgroud)

作为练习,您可以尝试(cerror ...)用显式restart-case构造替换。

然后,如果您测试代码,则应该看到调试器弹出并向您显示CONTINUE重新启动。如果您定义了自己的重启,则可以使用不同的名称。

调用重启

在您的skip-evenp函数中,您正在调用目前尚未建立的重新启动,我认为您对同时skip-evenp命名重新启动和函数感到困惑。

您应该做的是通过调用重新启动来处理错误。

在这里,您希望发出指示错误的代码继续,因此您确实不想取消执行堆栈。这就是为什么您必须使用HANDLER-BIND

(handler-bind ((evenp-error (lambda (e) (invoke-restart 'continue))))
  (filter-evenp '(1 2 3 4)))
1
3    
Run Code Online (Sandbox Code Playgroud)

您当然可以像您一样将匿名lambda提取到自定义函数中。


jki*_*ski 5

您需要将您的代码放到RESTART-CASE要重新开始执行的位置:

(defun filter-evenp (lst)
  (dolist (x lst)
    (restart-case
        (if (not (evenp x))
            (print x)
            (error 'evenp-error :text x))
      (skip-evenp () nil))))
Run Code Online (Sandbox Code Playgroud)

然后,您应该使用HANDLER-BIND该错误进行处理:

(handler-bind ((evenp-error #'skip-evenp))
  (filter-evenp (list 1 2 3 4 5)))
Run Code Online (Sandbox Code Playgroud)