> Function: limit proc z1 z2
>
> Proc must be a procedure taking a single inexact
argument.
>
> z2 should be chosen so that proc is expected to
be monotonic or
> constant on arguments between z1 and z1 + z2.
>
> Limit computes the limit of proc as its argument
approaches z1
> from z1 + z2. Limit returns a complex number
or real infinity
> or `#f'.
This I like a lot better.
> LIMIT was created so that static choices for
limit cases like:
>
> (expt 0 0)
==>
1
> or
> (expt 0 0)
==>
0/0
>
> don't necessitate workarounds when computing with functions like
> (lambda (x) (expt x x)):
>
> (limit (lambda (x) (expt x x)) 0 1e-9)
==> 1/0
Unfortunately, my experience is that
this approach is highly unreliable.
In the end, I spent more time doing
analytical sanity checks myself than
it took to write the proper numerical
code directly after understanding
the limits properly.
Example: An important function from
information theory is
f(x)
= -x log(x).
This function is in principle well behaved
(smooth, analytic, etc.) on (0,1],
but its derivative does not exist at
x = 0. Moreover, f(0) cannot directly be
computed numerically because the underflow
from log(x) is not cancelled by the
multiplication with zero. Practical
numerical code: IF x < xmin THEN 0 ELSE x log(x),
where xmin is chosen minimal such that
log(xmin) is an ordinary number and
not -infinity.
Using LIMIT in this case is not a good
idea for two reasons:
a) It is expensive and unnecessary,
except for very small x.
b) At least the reference implementation
of LIMIT doesn't get it right:
(limit
(lambda (x) (* -1 x (log x))) 0 1e-9) => -inf.0
This may be a bug in the reference implementation,
but it is certainly a
violation of the new specification as
f(x) is monotonic on [0,1/e].
When you try to fix the reference implementation,
you will find that it
cannot be fixed because it comes from
the "black box" procedure:
At a certain moment f(x) becomes -inf.0,
so that must be the limit.
I can relate another experience: The
Mathematica system has an operation
Limit[], which finds limits symbolically,
and a function NLimit[] which finds
limits numerically. Limits[] turns out
to be useful sometimes, but it took
many years and many releases until it
became something I nearly trust.
NLimits[] on the other hand is tricky,
even though it makes an effort to report
when it fails, e.g. NLimit[x Log[x],
x -> 0.] => "cannot recognize limit".
Bottom line: In the end, LIMIT might
do more harm than it is worth.
You might want to reconsider if it is
a feature that is essential for
the Scheme programming language itself.
Sebastian.