测试Guile函数中是否发生错误

时间:2014-02-03 02:17:54

标签: scheme guile

我正在尝试在Guile中创建一个函数,该函数测试一个任意表达式是否抛出错误,但是已经撞墙了。

(define (error-or-not qqx)
  (if
    (catch
      #t
      (lambda () ,qqx)
      (lambda (k . args) #t))
    #t
    #f))

(display (error-or-not `(/ 1 0))) ; => #t (1)
(newline)
(display (error-or-not `(/ 1 1))) ; => #t (2)
(newline)

qqx是一个quasiquoted表达式,在error-or-not函数内部进行求值,并进行测试以查看它是否会导致错误。

The Guile manual实际上说,如果评估qqx抛出错误,catch函数将返回从调用其第三个参数(带有参数的lambda)获得的值。如果qqx确实导致错误(参见上面的#1),这样可以正常工作。

但是手册还说如果没有错误,catch函数会返回评估qqx的值。这对我来说效果不佳,因为我无法区分这两种情况(见上文#2)。

有人可以指出如何明确告知错误没有发生吗?


更新

Chris Jester-Young指出了我的错误 - 请参阅下面接受的答案。为了完整起见,我发布了他正在使用的代码版本(向后移植到Guile 1.8.8):

(use-syntax (ice-9 syncase))

(define (stub retval) (lambda args retval))

(define-syntax error-or-not
  (syntax-rules ()
    ((_ expr ...)
      (catch #t (lambda () expr ... #f) (stub #t)))))

(display (error-or-not (/ 1 0))) ; => #t
(newline)
(display (error-or-not (/ 1 1))) ; => #f
(newline)

1 个答案:

答案 0 :(得分:2)

你在滥用quasiquoting;它不符合你的期望。特别是,它不能替代eval。您(lambda () ,qqx)创建的函数在调用时始终失败,因为unquote不能在quasiquote表单之外使用。

实现所需功能的最佳方式是宏:

(define-syntax-rule (error-or-not expr ...)
  (catch #t
         (lambda () expr ... #f)
         (const #t)))

示例:

(error-or-not (/ 1 0))   ; => #t
(error-or-not (/ 1 1))   ; => #f

Guile 1.8兼容版本:

(use-syntax (ice-9 syncase))
(define-syntax error-or-not
  (syntax-rules ()
    ((_ expr ...)
     (catch #t (lambda () expr ... #f)
               (lambda _ #t)))))