0

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?


Update

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)
Yawar
  • 11,272
  • 4
  • 48
  • 80
  • Your code does not evaluate at all, since you have a free (unquote) form outside quasiquoting. Have you really included all your code? – Dolda2000 Feb 03 '14 at 02:24
  • @Dolda2000 - I've updated to a single code sample that will evaluate. Thanks for pointing that out. – Yawar Feb 03 '14 at 02:35
  • As Chris Jester-Young pointed out in his answer, that still doesn't evaluate. The error message is `unquote: expression not valid outside of quasiquote in form (unquote qqx)`. Whatever are you doing to test that at all? – Dolda2000 Feb 03 '14 at 02:49
  • @Dolda2000 - thanks, I realise my error (pardon the pun) now. And to answer your question, I'm writing a unit-testing framework: GitHub:yawaramin/ggspec. – Yawar Feb 03 '14 at 03:08

1 Answers1

2

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)))))
C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • Thanks! That's clever. (Too bad about `unquote` though.) I'll update my question with your code, backported to Guile 1.8. – Yawar Feb 03 '14 at 03:00
  • I'll add a Guile 1.8-compatible version, though, the Guile team no longer supports 1.x versions, in case you didn't already know. :-) – C. K. Young Feb 03 '14 at 03:08
  • Ah, didn't know that, thanks, but I'm targeting 1.8 because it's distributed with older versions of GnuCash. – Yawar Feb 03 '14 at 03:09