123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- (use-modules
- (rnrs exceptions)
- (rnrs conditions))
- ;; =========
- ;; UTILITIES
- ;; =========
- (define even-simpler-display
- (lambda (sth)
- (display
- (simple-format
- #f "~a\n" sth))))
- ;; =====
- ;; INTRO
- ;; =====
- ;; Conditions are a concept from R6RS exception handling. A condition is created
- ;; using the constructor ~condition~ from R6RS or
- ;; Conditions can be "simple" or "compound". A simple condition describes a
- ;; single aspect of an exceptional situation. A compound condition contains a
- ;; list of simple conditions, which together describe multiple aspects of an
- ;; exceptional situation. The list of simple conditions of a compound condition
- ;; is called components of the compound condition.
- ;; Next let us see how we can work with conditions, when we get them.
- ;; ==========
- ;; CONDITIONS
- ;; ==========
- ;; The standard already defines a few constructors for so called standard
- ;; condition types:
- ;; - (make-message-condition message)
- ;; - (make-warning)
- ;; - (make-serious-condition) ; intended as supertype
- ;; - (make-violation)
- ;; - (make-assertion-violation)
- ;; - (make-irritants-condition irritants)
- ;; - (make-who-condition who)
- ;; - (make-non-continuable-violation)
- ;; - (make-implementation-restriction-violation)
- ;; - (make-lexical-violation)
- ;; - (make-syntax-violation form subform)
- ;; - (make-undefined-violation)
- ;; These have a predefined purpose, but probably already cover a lot of
- ;; ground. Lets try to make use of them:
- (define divide
- (lambda (a b)
- (cond
- [(= b 0)
- (raise ; raise from rnrs exceptions
- (condition
- (make-error)
- (make-message-condition "division by zero")
- (make-irritants-condition (list a b))
- (make-who-condition 'divide)))]
- [else
- (/ a b)])))
- (with-exception-handler
- (lambda (conditions-or-value)
- (even-simpler-display
- ;; We can get the simple conditions from a compound condition with the
- ;; `simple-conditions` getter.
- (simple-conditions conditions-or-value)))
- (lambda ()
- (divide 2 0))
- ;; We need to unwind the stack here. For explanation see the other examples.
- #:unwind? #t)
- ;; ======
- ;; GUARDS
- ;; ======
- ;; R6RS's or R7RS's guard expression is a wrapper around with-exception-handler
- ;; with #:unwind? set to #t. It is a macro enabling some convenience. The guard
- ;; expression allows for a cond expression, which enables to specify different
- ;; handlers for different exception.
- (guard
- ;; First a binding is defined, which will be bound to the raised
- ;; object. This can be a condition or a raised value.
- (con
- ;; First we check, whether the condition is an error. This could be a
- ;; compound condition, which contains a simple condition produced by
- ;; `make-error`, or it could be only a simple condition produced by
- ;; `make-error`.
- [(error? con)
- (if (message-condition? con)
- (even-simpler-display (condition-message con))
- (even-simpler-display "an error has occurred"))
- ;; We also return the symbol 'error, to signal, that some kind of error
- ;; occurred to whatever expects a return value from the guard form.
- 'error]
- ;; We can in other cases of the guard check for different errors.
- [(violation? con)
- (if (message-condition? con)
- (even-simpler-display (condition-message con))
- (even-simpler-display "the program has a bug"))
- 'violation])
- ;; Write something here, which could cause an exceptional situation.
- (raise
- (condition
- (make-error)
- (make-message-condition "I am an error"))))
- ;; If no branch of the guard catches the condition, it will be raised again.
- (guard
- (con
- ((error? con)
- (if (message-condition? con)
- (display (condition-message con))
- (display "an error has occurred"))
- 'error))
- (raise
- (condition
- (make-violation
- (make-message-condition "I am an error")))))
- ;; Another example:
- (guard
- (con
- [(error? con)
- (if (message-condition? con)
- (even-simpler-display (condition-message con))
- (even-simpler-display "an error has occurred"))
- 'error]
- [else])
- (divide 314 0))
- ;; Advantages of using `guard`: We can see, that the guard makes it unnecessary
- ;; to wrap the code we want to run in a lambda to delay evaluation. This is
- ;; taken care of by the guard form itself. Also the guard form already provides
- ;; the cond like structure, so there is no need to write a cond.
|