use*_*063 5 exception restart common-lisp conditional-statements condition-system
我已经阅读了几天时间的通用Lisp“ Practical Common Lisp”异常处理一章,但是现在我对示例和解释感到困惑,与此同时,我尝试编写一些测试示例,但是由于我不起作用意料之中,以下是我的测试样本。
条件定义
(define-condition evenp-error (error)
((text :initarg :text :reader text)))
Run Code Online (Sandbox Code Playgroud)定义打印奇数的函数
(defun filter-evenp (lst)
(dolist (x lst)
(if (not (evenp x))
(print x)
(error 'evenp-error :text x))))
Run Code Online (Sandbox Code Playgroud)重启功能
(defun skip-evenp (c) (invoke-start 'skip-evenp))
Run Code Online (Sandbox Code Playgroud)重新启动案例
(restart-case (filter-evenp (list 1 2 3 4 5))
(skip-evenp () nil))
Run Code Online (Sandbox Code Playgroud)我要做的就是打印所有奇数并跳过偶数错误,我的样本出了什么问题?有人帮忙吗?提前谢谢了!!
实用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提取到自定义函数中。
您需要将您的代码放到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)