Common Lisp状况系统(condition system)的学习和理解

• 状况系统是这样的:底层代码产生状况---》中层代码制定多种恢复策略-》上层代码处理并选择中层的恢复策略

• 将从错误中恢复的代码与决定选择如何恢复进行分离,也就是说,错误恢复方法在底层提供了,选择哪个进行恢复的选择权交给高层函数。

• 状况系统使得我们在写底层功能函数时只关注函数功能即要完成的事情,而对于错误的恢复方法都在中下层提供,高层拥有最后的选择权。另外,状况系统使得我们在遇到错误的时候不必转到调试器而停止,而是进入预想的错误处理的方法中。

• 以下是处理函数对抛出的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,我们在不同的高层函数中选择不同的策略进行处理,得到了不同的结果。
python+opencv简谱识别音频生成系统源码含GUI界面+详细运行教程+数据 一、项目简介 提取简谱中的音乐信息,依据识别到的信息生成midi文件。 Extract music information from musical scores and generate a midi file according to it. 二、项目运行环境 python=3.11.1 第三方库依赖 opencv-python=4.7.0.68 numpy=1.24.1 可以使用命令 pip install -r requirements.txt 来安装所需的第三方库。 三、项目运行步骤 3.1 命令行运行 运行main.py。 输入简谱路径:支持图片或文件夹,相对路径或绝对路径都可以。 输入简谱主音:它通常在第一页的左上角“1=”之后。 输入简谱速度:即每分钟拍数,同在左上角。 选择是否输出程序中间提示信息:请输入Y或N(不区分大小写,下同)。 选择匹配精度:请输入L或M或H,对应低/中/高精度,一般而言输入L即可。 选择使用的线程数:一般与CPU核数相同即可。虽然python的线程不是真正的多线程,但仍能起到加速作用。 估算字符上下间距:这与简谱中符号的密集程度有关,一般来说纵向符号越稀疏,这个值需要设置得越大,范围通常在1.0-2.5。 二值化算法:使用全局阈值则跳过该选项即可,或者也可输入OTSU、采用大津二值化算法。 设置全局阈值:如果上面选择全局阈值则需要手动设置全局阈值,对于.\test.txt中所提样例,使用全局阈值并在后面设置为160即可。 手动调整中间结果:若输入Y/y,则在识别简谱后会暂停代码,并生成一份txt文件,在其中展示识别结果,此时用户可以通过修改这份txt文件来更正识别结果。 如果选择文件夹的话,还可以选择所选文件夹中不需要识别的文件以排除干扰
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值