[Haskell-cafe] Proposal for restructuring Number classes
Henning Thielemann
lemming at henning-thielemann.de
Mon Apr 10 08:17:09 EDT 2006
On Mon, 10 Apr 2006, Andrew U. Frank wrote:
> there has been discussions on and off indicating problems with the structure
> of the number classes in the prelude. i have found a discussion paper by
> mechveliani but i have not found a concrete proposal on the haskell' list of
> tickets. i hope i can advance the process by making a concrete proposal for
> which i attach Haskell code and a pdf giving the rational can be found at
> ftp://ftp.geoinfo.tuwien.ac.at/frank/numbersPrelude_v1.pdf
Why are Zeros and Ones separated from the classes providing the
operations? Since groups are required to have a neutral element and rings
must have both a neutral additive element and a neutral multiplicative
element, it makes sense to me, to couple Additive group with a zero and a
Ring structure with a one. I guess you want to separate them because there
are vectors and matrices of different sizes which we subsume under the
same Haskell type. I have not seen a convincing solution for this problem
so far. Indeed there are proposals implicit parameters, local type class
instances and so on. The problem arises also for residue classes.
I have worked around that problem by not comparing with a generated zero,
but use a special isZero method. If I need a zero or a one in an algorithm
I make it a parameter of the algorithm. Sometimes this leads to a nice
generalization of an algorithm, if callers provide values different from
zero.
gcd+lcm, quot+rem, div+mod:
In NumericPrelude quot+rem and div+mod are in separate classes. 'quot'
and 'rem' need a notion of rounding towards zero. They are less general
than 'div' and 'mod'. Actually I have never found an appriopriate
application of 'quot' and 'rem'. When I saw them in other programs, 'div'
or 'mod' were always the better choice. Also in NP 'gcd' and 'lcm' are
separated from 'div' and 'mod', because the greatest common divisor cannot
be always computed by the Euclidean algorithm.
(^), (^^), (**):
I found the distinctions of powers very useful and I would even refine
them. In mathematical notation we don't respect types and we do not
distinguish between powers of different types. However if we assume the
most general types for both basis and exponent, the result of the power is
no longer unique. Actually all possible solutions of say 1^x, where x is
irrational is dense in the complex unit circle. In the past I needed the
power of two complex numbers only once, namely for the Cauchy wavelet:
f(t) = (1- i*k*t) ^ (-1/2 + mu2/k + i*mu1)
http://www.math.uni-bremen.de/~thielema/Research/cwt.pdf
http://ieeexplore.ieee.org/iel5/78/18506/00852022.pdf?arnumber=852022
However, I could not use the built-in complex power function because the
resulting function became discontinuous. Of course, powers of complex
numbers have the problem of branch cuts and the choice of the branch built
into the implementation of the complex power is quite arbitrary and might
be inappropriate.
But also for real numbers there are problems: For computing
(-1)**(1/3::Double) the power implementation has to decide whether
(1/3::Double) is close enough to a third. If it does so it returns (-1)
otherwise it fails. However, why shall 0.333333333333333 represent 1/3? It
may be really meant as 333333333333333/10^15, and a real 10^15th root of
(-1) does not exist.
So I propose some balancing: The more general the basis the less general
the exponent and vice versa. I also think the following symbols are more
systematic and intuitive:
any ring (provides *) ^ cardinal
any field (provides /) ^- integer
an algebraic field ^/ rational (computing a list of powers
depending on the denominator
of the rational)
positive real
(including transcendent) ^? anything (unqiue via exponential series)
That is (^-) would replace (^^), (^?) would replace (**), (^) remains and
(^/) is new.
Branch cuts are a problem for all functions based on logarithms, apart
from log and (**) these are: asin, acos, atan, asinh, acosh, atanh. I
wonder how to treat them. I thought whether a residue class type would
help. However a residue class with respect to the transcendent number pi
would lead to a lot of rounding problems and the residue classes could be
hardly processed further. So I'm thinking about a logarithm which returns
a list of possible solutions. However for real numbers the logarithm is
unique. I come to the conclusion that real logarithms and associated
functions are considerably different from there generalizations to complex
numbers. How to resolve that in type classes?
More information about the Haskell-Cafe
mailing list