1

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

(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 消息Unbound variable: ~S如何获取实际的错误消息而不是模板?
  • 卡瓦例外: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 核心转储
  • 开局冻结

注意:这是 REPL 的一部分,我正在系统上的所有 Scheme 实现中测试它。它几乎可以工作,它可以自行运行,但我想在发生异常时显示正确的错误消息,而不是退出 REPL。

4

3 回答 3

1

Gauche 核心转储

哎呀。当然,这并不理想,但可以解释。

  • 默认情况下,with-exception-handler由于历史原因,Gauche 是 SRFI-18,而不是 R7RS。这意味着在发生异常的动态环境中调用异常处理程序,包括异常处理程序设置。如果异常处理程序中发生异常,则调用相同的异常处理程序,从而导致无限递归。显然 Gauche 的运行时会吃掉 C 堆栈或其他东西。
  • error-object-messageGauche 的默认命名空间中没有定义。所以这首先会触发一个异常。

添加

(import (scheme base) (scheme write) (scheme r5rs))

在代码的开头使程序在 R7RS 绑定中运行。然后你会得到:

unbound variable: xxx 

实际上,您的代码不是有效的 R7RS 程序(应以至少一个import声明开头),因此任何事情都可能发生,这取决于实现中不合格代码的默认解释。

[编辑] 恕我直言,with-exception-handler应被视为构建易于使用的实用程序的最低级别结构,因此应格外小心。在一般用例中,guard提供了一个很好的抽象。

于 2021-01-11T23:34:20.953 回答
1

您使用 Gambit 获得无限循环的原因是该变量未绑定,因此使用对象调用xxx异常处理程序,这会导致调用但参数不是(特定于调用过程引发的异常)) 所以这会引发一个对象,该对象会导致调用相同的异常处理程序,以此类推。(lambda (e) (exit (error-object-message e)))unbound-global-exceptionerror-object-messageerror-objecterrortype-exception

如果您想要一个“弹出”当前异常处理程序的异常处理,请使用with-exception-catcher而不是with-exception-handler. 这将避免无限循环。

在 Gambit 中可以通过以下方式将异常对象转换为字符串:

(define (exception->string exc)
  (with-output-to-string
    (lambda ()
      (display-exception exc))))

它适用于error-objects其他类型的异常,也适用于任何非异常对象。

这是一个更便携的解决方案(经过表面测试):

(import (scheme base)
        (scheme r5rs))

(cond-expand
  ((or lips kawa gauche)
   (define (exception->string exc)
     (error-object-message exc)))
  (gambit
   (define (exception->string exc)
     (with-output-to-string
       (lambda ()
         (display-exception exc)))))
  (guile
   (import (rnrs base)
           (rnrs exceptions)
           (rnrs conditions))
   (define (exception->string exc)
     (condition-message exc))))

(define (evaluate expr env)
  (call-with-current-continuation
   (lambda (exit)
     (with-exception-handler
      (lambda (e)
        (exit (exception->string e)))
      (lambda ()
        (eval expr env))))))

(display (evaluate 'xxx (interaction-environment)))
(newline)
于 2021-01-12T16:24:32.340 回答
0

对于卡瓦:

   (define (exception->string exc)
     (call-with-port (open-output-string)
                     (lambda (port)
                       (display exc port)
                       (get-output-string port)))))

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

于 2021-01-14T08:49:21.467 回答