问题描述
(cond-expand
(gambit)
(gauche)
(kawa)
(guile
(import (rnrs base)
(rnrs exceptions)
(rnrs conditions))
(define (error-object-message cond)
(condition-message cond))))
(define (evaluate expr env)
(call-with-current-continuation
(lambda (exit)
(with-exception-handler
(lambda (e)
(exit (error-object-message e)))
(lambda ()
(eval expr env))))))
;; trigger error
(display (evaluate 'xxx (interaction-environment)))
(newline)
- Guile message
Unbound variable: ~S
如何获取实际的错误消息而不是模板? - Kawa 异常:
Argument #1 'unbound location: xxx' to 'error-object-message' has wrong type (gnu.mapping.UnboundLocationException) (gnu.mapping.UnboundLocationException cannot be cast to kawa.lang.NamedException)
- Gauche 核心转储
- gambit 冻结
注意:这是 REPL 的一部分,我正在我系统上的所有 Scheme 实现中测试它。它几乎可以工作,它可以自行运行,但我想在发生异常时显示正确的错误消息,而不是退出 REPL。
解决方法
Gauche 核心转储
糟糕。当然,这并不理想,但可以解释。
- 默认情况下,由于历史原因,Gauche 的
with-exception-handler
是 SRFI-18,而不是 R7RS。这意味着在异常发生的动态环境中调用异常处理程序,包括异常处理程序设置。如果异常处理程序中发生异常,则调用相同的异常处理程序,从而导致无限递归。显然 Gauche 的运行时占用了 C 堆栈或其他东西。 -
error-object-message
未在 Gauche 的默认命名空间中定义。所以这首先会触发异常。
添加
(import (scheme base) (scheme write) (scheme r5rs))
在代码的开头使程序在 R7RS 绑定中运行。然后你会得到:
unbound variable: xxx
实际上,您的代码不是有效的 R7RS 程序(应至少以一个 import
声明开头),因此任何事情都可能发生,具体取决于实现中不符合规范的代码的默认解释。
[编辑] 恕我直言,with-exception-handler
应被视为构建易于使用的实用程序的最低级别结构,因此应格外小心地使用。在一般用例中,guard
提供了很好的抽象。
对于卡瓦:
(define (exception->string exc)
(call-with-port (open-output-string)
(lambda (port)
(display exc port)
(get-output-string port)))))
这会将异常转换为字符串并获取错误消息