如何在 Scheme 中显示来自 eval 的错误消息?

问题描述

我正在尝试创建计算表达式并将错误作为错误字符串返回的代码

(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)))))

这会将异常转换为字符串并获取错误消息