Parenthesized sentences may or may not belong to Scheme, depending on
whether or not they are legal according to the grammar in
figure
. If DrScheme verifies that a sentence does
not belong to the language dubbed Beginning Student, it signals a
SYNTAX ERROR.
The remaining expressions are syntactically legal, but some of those may
still pose problems for our evaluation rules. We say that such legal
expressions contain LOGICAL ERRORS
or RUN-TIME ERRORS.
Consider the simplest example: (/ 1 0). We already know from
mathematics that
does not have a value. Clearly, since Scheme's calculations must be consistent with mathematics, it too must not equate (/ 1 0) with a value.
In general, if an expression is not a value and if the evaluation rules allow no further simplification, we say that an error occurred or that the function raises an error signal. Pragmatically this means that the evaluation stops immediately with an appropriate error message, such as ``/: divide by zero'' for division by zero.
For an example, consider the following evaluation:
(+ (* 20 2) (/ 1 (- 10 10))) = (+ 40 (/ 1 0)) = /: divide by zeroThe error eliminates the context (+ 40 ...) around (/ 1 0), which represents the remainder of the computation with respect to the division.
To understand how run-time errors are signaled, we must inspect the evaluation rules again. Consider the function
;; my-divide : number -> number
(define (my-divide n)
(cond
[(= n 0) 'inf]
[else (/ 1 n)]))
Now suppose we apply my-divide to 0. Then the first step is:
(my-divide 0)It would obviously be wrong to say that the function signals the error ``/: divide by zero'' now, even though an evaluation of the underlined subexpression would demand it. After all, (= 0 0) is true and therefore the application has a proper result:= (cond [(= 0 0) 'inf] [else
])
(my-divide 0)= (cond [(= 0 0) 'inf] [else
])
= (cond [true 'inf] [else
])
= 'inf
Fortunately, our laws of evaluation take care of these situations automatically. We just need to keep in mind when the laws apply. For example, in
(+ (* 20 2) (/ 20 2))the addition cannot take place before the multiplication or division. Similarly, the underlined division in
(cond [(= 0 0) 'inf] [elsecannot be evaluated until the corresponding line is the first condition in the cond-expression.])
As a rule of thumb, it is best to keep the following in mind:
| Guideline on Expression Evaluation Simplify the outermost (and left-most) subexpression that is ready for evaluation. |
While this guideline is a simplification, it always explains Scheme's results.
In some cases, programmers also want to define functions that raise errors.
Recall the checked version of area-of-disk from
section
:
;; checked-area-of-disk : Scheme-value -> boolean
;; to compute the area of a disk with radius v, if v is a number
(define (checked-area-of-disk v)
(cond
[(number? v) (area-of-disk v)]
[else (error 'checked-area-of-disk ``number expected'')]))
If we were to apply checked-area-of-disk to a symbol, we would get
the following evaluation:
(- (checked-area-of-disk 'a)
(checked-area-of-disk 10))
= (- (cond
[(number? 'a) (area-of-disk 'a)]
[else (error 'checked-area-of-disk ``number expected'')])
(checked-area-of-disk 10))
= (- (cond
[false (area-of-disk 'a)]
[else (error 'checked-area-of-disk ``number expected'')])
(checked-area-of-disk 10))
= (- (error 'checked-area-of-disk ``number expected'')
(checked-area-of-disk 10))
= checked-area-of-disk : number expected
In other words, when we evaluate an the error expression, we
proceed as if we had encountered a division by zero.