我正在尝试在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)
答案 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)))))