I'm trying to create a function in Guile which tests if an arbitrary expression threw an error or not, but have hit a wall.
(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
is a quasiquoted expression that is evaluated inside the error-or-not
function and tested to see if it causes an error.
The Guile manual in effect says that, if evaluating qqx
throws an error, the catch
function returns the value it gets from calling its third argument (the lambda which takes the arguments). This works fine if qqx
actually does cause an error (see above #1).
But the manual also says that if there is no error, the catch
function returns the value from evaluating qqx
. This is not working out so well for me because I can't distinguish between the two cases (see above #2).
Can someone point out how to definitively tell when an error did not occur?
Chris Jester-Young has pointed out my mistake--see the accepted answer below. For completeness, I'm posting the version of his code I'm using (backported to 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)
You are misusing quasiquoting; it doesn't do what you expect. In particular, it isn't a substitute for eval
. The (lambda () ,qqx)
you have creates a function that always fails when called, because unquote
cannot be used outside of a quasiquote
form.
The best way to implement the functionality you want is as a macro:
(define-syntax-rule (error-or-not expr ...)
(catch #t
(lambda () expr ... #f)
(const #t)))
Example:
(error-or-not (/ 1 0)) ; => #t
(error-or-not (/ 1 1)) ; => #f
Guile 1.8-compatible version:
(use-syntax (ice-9 syncase))
(define-syntax error-or-not
(syntax-rules ()
((_ expr ...)
(catch #t (lambda () expr ... #f)
(lambda _ #t)))))