0

我正在尝试在 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函数内部进行评估并测试它是否会导致错误。

Guile 手册实际上说,如果评估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)
4

1 回答 1

2

你在滥用准引用;它不符合您的期望。特别是,它不能替代eval. (lambda () ,qqx)您创建了一个在调用时总是失败的函数,因为不能unquotequasiquote表单之外使用。

实现所需功能的最佳方法是作为宏:

(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)))))
于 2014-02-03T02:36:49.300 回答