如何在Common Lisp中捕获错误消息?

时间:2019-01-22 12:18:37

标签: common-lisp sbcl

我无法捕获REPL中打印的错误消息,我希望将其作为字符串或以后可以打印的任何其他类型,在Common Lisp中可以吗?这是其他语言(例如Javascript)中的常见现象:

var myError = undefined;
try {
    some();
}catch(e){
    myError = e.message;
}

当然,在Common Lisp中这将无法正常工作,毕竟它不会像JavaScript中那样返回错误对象,但是我想知道是否有任何方式可以捕获错误消息,因此我不需要打印它错误何时发生,但何时发生。

我正在使用: SBCL

我正在尝试:

CL-USER> (handler-case (/ 3 0)
  (division-by-zero (c)
    (defvar *my-error* c)))
; in: HANDLER-CASE (/ 3 0)
;     (/ 3 0)
;
; caught STYLE-WARNING:
;   Lisp error during constant folding:
;   arithmetic error DIVISION-BY-ZERO signalled
;   Operation was (/ 3 0).
;
; compilation unit finished
;   caught 1 STYLE-WARNING condition
*MY-ERROR*
CL-USER> *my-error*
#<DIVISION-BY-ZERO {1004486093}>

我要捕获的是以下消息,稍后打印:

; in: HANDLER-CASE (/ 3 0)
;     (/ 3 0)
;
; caught STYLE-WARNING:
;   Lisp error during constant folding:
;   arithmetic error DIVISION-BY-ZERO signalled
;   Operation was (/ 3 0).
;
; compilation unit finished
;   caught 1 STYLE-WARNING condition

2 个答案:

答案 0 :(得分:3)

CL-USER> (write *my-error* :escape nil)
arithmetic error DIVISION-BY-ZERO signalled
Operation was (/ 3 0).
#<DIVISION-BY-ZERO {100369B843}>

使用format指令,~a可以实现同样的效果:

CL-USER> (with-standard-io-syntax (format nil "~a" *my-error*))
"arithmetic error DIVISION-BY-ZERO signalled
Operation was (/ 3 0)."

请注意,您正在使用defvar,因此,如果两次执行相同的代码,则不会分配变量。更好地定义一个返回字符串并使用局部变量的函数。

  

我要捕获的是以下消息

该消息特定于您的环境如何打印错误消息,捕获起来更加困难,也许您可​​以绑定自己的字符串流并捕获整个输出(?),但我不建议这样做。 / p>

答案 1 :(得分:1)

您确实捕获了这种情况,因此可以重现 error 消息,但是看来您想捕获 SBCL编译警告。因此,它与条件无关。

我没有解决方案,但是您应该从另一个方向搜索IMO(如何捕获SBCL警告等)。

如前所述,您不应使用defvar。即使以前没有setf变量,也可以改用defvar。在这种情况下,您将收到另一个警告:

; in: HANDLER-CASE (/ 3 0)
;     (SETF *MY-ERROR* C)
; ==>
;   (SETQ *MY-ERROR* C)
; 
; caught WARNING:
;   undefined variable: *MY-ERROR*
; 
; compilation unit finished
;   Undefined variable:
;     *MY-ERROR*
;   caught 1 WARNING condition
;   caught 1 STYLE-WARNING condition

顺便说一句,看来您使用的是菜谱,不是吗? :)