A numeric expression can be reasonably reduced to give:
A1. A mathematically precise result.
A2. An equivalence class of values which is known to contain the result.
A3. The information that no value can exist (even with the addition of
new axioms) which serves as the result (without creating an
inconsistency).
A4. The information that the axiomatic system in play does not
decide the result but new axioms could define a value.
A5. The information that either (A3) or (A4) is true.
A6. No information -- reduction does not terminate.
The domain of numeric expressions should include
all equivalence classes which can be produced by other
numeric expressions. An expression operating on an
equivalence class can produce:
B1. A mathematically precise result that is invariant regardless
of what member of the equivalence set is chosen.
B2. A mathematically precise equivalence class which contains
all the results that come from choosing any member of
the input equivalence class but contains no other values.
B3. An equivalence class which is known only to be a
(possibly improper) superclass of (B2).
B4. The information that no (B2) answer can exist without
creating inconsistency.
B5. The information that no (B2) is decided by the axioms
in play but that new consistent axioms could define
such a value.
B6. The information that either (B4) or (B5) is true.
B7. No information -- reduction does not terminate.
I'm ignoring gross type errors here. For example, my lists
above don't talk about the reduction of (+ 'a 1).
Two examples:
In an implementation without exact rationals but with
IEEE inexact floats, (/ 1 3) follows case A2.
(+ (/ 1 3) (/ 1 3)) follows case B3.
(> (/ 1 3) 0) follows case B1.
The expression 1.0 (in R6) follows case B2.
A new type is needed: numeric-expr-result? which is a
(possibly improper) superclass of number?.
A new type is needed: boolean-expr-result? which
is a (possibly improper) superclass of boolean?.
Cases A2..A4 and B2..B6 should always throw
continuable exceptions. If the exception is continued,
values supplied to that continuation serve as the
return values of the expression throwing the exception
however it is an error if any of those values are not
numeric-expr-result? or boolean-expr-result? as
appropriate.
The default environment should define exception
handlers which, in effect, implement the IEEE-defined
behavior endorsed by R6.
So, for example, the primitive number? should
be defined such that (number? +inf.0) throws an
exception which, by default, is handled by resuming
from the exception and return #t. However, programs
should be able to alter that behavior by altering the
dynamic context of evaluation (changing the exception
handler). Similarly, (/ 1.0 0.0) should throw an exception
which the default handler happens to handle by
resuming and returning +inf.0. Of course,
(numeric-expr-result? +inf.0) should return #t
(as must any return value from /).
Why build in this degree of generalness? This level
of extensibility? Why allow so much ambiguity into
the outcome of an expression like "(/ X Y)"?
Mainly because a lot of useful math can be done
just sticking to the algebraic or similar properties
characteristically associated with an operator like "/"
without committing to any specific semantics -- and
we know that there are multiple, useful semantics.
So, you asked, for example, why anyone in their right
mind would think (= +inf.0 +inf.0) deserved a #t or #f
rather than an error. Well, it depends on what, if any
meaning is assigned to the +inf.0s and more than one
reasonable meaning is possible, including both #t and
#f. So raise an exception. Asked to compute (= +inf.0 +inf.0)
Scheme should dynamically raise the question:
"Well, what do you mean exactly?"
Also, and this should make sense if you follow the above,
there should be types like +inf.0? of which +inf.0 is
merely a representative member.
-t
_______________________________________________
r6rs-discuss mailing list
[email protected]
http://lists.r6rs.org/cgi-bin/mailman/listinfo/r6rs-discuss