[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