Common Lisp状况系统(condition system)的学习和理解
程序员文章站
2024-01-09 21:20:22
...
• 状况系统是这样的:底层代码产生状况---》中层代码制定多种恢复策略-》上层代码处理并选择中层的恢复策略
• 将从错误中恢复的代码与决定选择如何恢复进行分离,也就是说,错误恢复方法在底层提供了,选择哪个进行恢复的选择权交给高层函数。
• 状况系统使得我们在写底层功能函数时只关注函数功能即要完成的事情,而对于错误的恢复方法都在中下层提供,高层拥有最后的选择权。另外,状况系统使得我们在遇到错误的时候不必转到调试器而停止,而是进入预想的错误处理的方法中。
• 以下是处理函数对抛出的error的简单的处理方式:
结果为:
((1 "odd") (2 "even") (3 "odd") (4 "even") (5 "odd") (6 "even") (7 "odd") (8 "even") (9 "odd") (10 "even"))
• restart-case可以有多个,每次抛出error,调用栈都会跳出多个restart让你选择,处理的方法是调用invoke-restart来主动选择重启策略,这个选择我们在高层函数中利用handler-bind对错误类型和处理函数进行绑定,这就使得我们可以在中层和底层代码中制定多种重启策略,在不同的高层函数中选择不同的处理策略,以下是我改写的书上例子,目的是要理解多个restart-case的运行方式:
• 分别运行log-analyzer-skip log-analyzer-reparse log-analyzer-use,结果为:
(("a" "odd") (2 "even") ("a" "odd") (4 "even") ("a" "odd") (6 "even") ("a" "odd") (8 "even") ("a" "odd") (2 "even") )
((12 "even") (2 "even") (14 "even") (4 "even") (16 "even") (6 "even") (18 "even") (8 "even") (20 "even") (10 "even"))
((1 "odd") (2 "even") (3 "odd") (4 "even") (5 "odd") (6 "even") (7 "odd") (8 "even") (9 "odd") (10 "even"))
可见,对于同一种condition,我们在不同的高层函数中选择不同的策略进行处理,得到了不同的结果。
• 将从错误中恢复的代码与决定选择如何恢复进行分离,也就是说,错误恢复方法在底层提供了,选择哪个进行恢复的选择权交给高层函数。
• 状况系统使得我们在写底层功能函数时只关注函数功能即要完成的事情,而对于错误的恢复方法都在中下层提供,高层拥有最后的选择权。另外,状况系统使得我们在遇到错误的时候不必转到调试器而停止,而是进入预想的错误处理的方法中。
• 以下是处理函数对抛出的error的简单的处理方式:
(define-condition malformed-log-entry-error (error) ((test :initarg :text :reader text))) (defun parse-log-entry (text) (if (evenp text) text (error 'malformed-log-entry-error :text text))) (defun parse-log-file () (loop for i from 1 to 10 do (handler-case (parse-log-entry i) (malformed-log-entry-error(var) (text var))))
结果为:
((1 "odd") (2 "even") (3 "odd") (4 "even") (5 "odd") (6 "even") (7 "odd") (8 "even") (9 "odd") (10 "even"))
• restart-case可以有多个,每次抛出error,调用栈都会跳出多个restart让你选择,处理的方法是调用invoke-restart来主动选择重启策略,这个选择我们在高层函数中利用handler-bind对错误类型和处理函数进行绑定,这就使得我们可以在中层和底层代码中制定多种重启策略,在不同的高层函数中选择不同的处理策略,以下是我改写的书上例子,目的是要理解多个restart-case的运行方式:
(define-condition malformed-log-entry-error (error) ((test :initarg :text :reader text))) (defun parse-log-entry (text) (if (evenp text) (list text "even") (error 'malformed-log-entry-error :text text))) (defun parse-log-file () (loop for i from 1 to 10 for entry = (restart-case (parse-log-entry i);;提供三个restart-case (skip-log-entry () "a") (use-value (v) (list v "odd")) (reparse-entry (fixed-text) (parse-log-entry fixed-text))) when entry collect it)) (defun analyze-log () (print (parse-log-file))) (defun skip-log-entry (c) (let ((restart (find-restart 'skip-log-entry))) (when restart (invoke-restart restart)))) (defun use-value-p (c) (use-value (text c))) (defun reparse-log-entry (c) (let ((reparse (find-restart 'reparse-entry))) (when reparse (invoke-restart reparse (+ (text c) 11))))) ;;在高层函数中,根据不同的情况选择不同的再启动策略 (defun log-analyzer-skip () (handler-bind ((malformed-log-entry-error #'skip-log-entry)) (analyze-log))) (defun log-analyzer-use () (handler-bind ((malformed-log-entry-error #'use-value-p)) (analyze-log))) (defun log-analyzer-reparse () (handler-bind ((malformed-log-entry-error #'reparse-log-entry)) (analyze-log)))
• 分别运行log-analyzer-skip log-analyzer-reparse log-analyzer-use,结果为:
(("a" "odd") (2 "even") ("a" "odd") (4 "even") ("a" "odd") (6 "even") ("a" "odd") (8 "even") ("a" "odd") (2 "even") )
((12 "even") (2 "even") (14 "even") (4 "even") (16 "even") (6 "even") (18 "even") (8 "even") (20 "even") (10 "even"))
((1 "odd") (2 "even") (3 "odd") (4 "even") (5 "odd") (6 "even") (7 "odd") (8 "even") (9 "odd") (10 "even"))
可见,对于同一种condition,我们在不同的高层函数中选择不同的策略进行处理,得到了不同的结果。