HANDLER-CASE替代品不是宏观

Dan*_*rov 3 common-lisp

请考虑以下代码:

(define-condition some-condition (error) nil)

(defmethod print-object ((obj some-condition) stream)
  (format stream "HELLO THERE"))

(defmacro error-report-test-aux (fn-to-cause-error error-type-to-catch fn-to-handle-error expected-message)
  `(let ((result-message
           (handler-case (funcall ,fn-to-cause-error)
             (,error-type-to-catch (e) (funcall ,fn-to-handle-error e)))))
     (assert (string= result-message
                      ,expected-message))
     t))
Run Code Online (Sandbox Code Playgroud)

我可以像这样使用它:

(error-report-test-aux (lambda () (error 'some-condition)) 
                       some-condition 
                       #'princ-to-string 
                       "HELLO THERE")
Run Code Online (Sandbox Code Playgroud)

但我想创建error-report-test-aux一个函数而不是宏,这样我就可以在变量中传递一种条件.

简单地编写defun代替defmacro和删除反引号和逗号不起作用,因为handler-case它是宏并且它不会评估error-type-to-catch.

我的问题是:是否有类似的东西handler-case会评估它的参数(特别是条件类型参数)?

sds*_*sds 5

是和否:-)

,你的确切问题

没有标准函数可以执行您想要的操作,因为捕获错误需要建立绑定,并且通常需要绑定常量符号(例如在let/中let*),因为它更容易优化.

可以考虑创建一个"通用"处理程序handler-bind,然后拒绝处理"不感兴趣"的条件(如评论中的@jkiiski所示),但我不确定这是否符合您的确切要求(未经测试!):

(defun error-report-test-aux (fn-to-cause-error error-type-to-catch expected-message)
  (catch 'trap
    (handler-bind ((error
                    (lambda (condition)
                      (when (typep condition error-type-to-catch)
                        (throw 'trap (string= (princ-to-string condition)
                                              expected-message))))))
      (funcall fn-to-cause-error))))
Run Code Online (Sandbox Code Playgroud)

是的,特定于实施

如果您的实现实现handler-case/handler-bind通过绑定内部全局变量,您可以使用progv自己绑定它,从而实现您error-report-test-aux的功能.

这可能不是最好的想法(您的代码变得与特定实现结合).

是的,有点

您可以使用some-condition命名CLOS类并使用泛型函数而不是宏的事实.