[plt-scheme] raising / handling errors
> I know(?) how to use with-handlers to catch exististing exceptions, and
> in fact, I do this (now) in my read/eval/print loop. But it is not all
> clear (to me) how to go about raising exceptions and handling them. I am
> aware of raise and error, but I'd like to be able to raise an exception
> which will be caught by a handler I install. I recall reading that, say,
> exn:fail:contract:arity corresponds to the predicate
> exn:fail:contract:arity?
Hi Greg,
Here's a small example; let's say that we're writing a function that only
works with numbers and we'd like to raise a you-are-silly exception if we
give that function something else. (We really should use contracts here,
but let's ignore that for the moment.)
Let's first define a "you-are-silly" kind of exception. We can do this by
defining an exn:fail:you-are-silly structure:
;;;;;;
> (define-struct (exn:fail:you-are-silly exn:fail) ())
;;;;;;
We're subtyping on exn:fail to make it a little easier to trap it
generically: we might want to trap things by saying something like:
(with-handlers ((exn:fail? ...)) ...)
in which case, if we raise an exn:fail:you-are-silly, things are still
going to work ok because exn:fail:you-are-silly is a subtype of exn:fail.
But how do we construct an instance of an exn:fail:you-are-silly
structure? If we look at Chapter 6 of the reference:
http://download.plt-scheme.org/doc/mzscheme/mzscheme-Z-H-6.html#node_chap_6
then we can see a description on primitive exceptions in Section 6.1.1.
A main thing to note is that the base 'exn' structure has two fields.
'exn:fail' doesn't introduce any other fields, so that means that our
'exn:fail:you-are-silly constructor' also takes in only two fields:
* message
* continuation-marks
We can experimentally see this:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (procedure-arity make-exn:fail:you-are-silly)
2
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
but it's good to know what those two fields mean too. *grin*
Ok, so let's try this:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (make-exn:fail:you-are-silly
"you silly head"
(current-continuation-marks))
#<struct:exn:fail:you-are-silly>
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
There's our exception object. Its only a matter now of raising it
whenever we want to castigate the caller.
Let's turn this into a procedure and test this out:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (define (raise-you-silly)
(raise (make-exn:fail:you-are-silly
"you silly head"
(current-continuation-marks))))
> (define (test x)
(cond
[(number? x) (* x x)]
[else (raise-you-silly)]))
> (test 42)
1764
> (test 'muhahah)
you silly head
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
I hope this helps!