Why does the class called "Real" support only rationals, and not all reals?

I just got started learning Haskell a few days ago. I've implemented a numeric data type that can represent some irrational numbers exactly, and I'd like to instantiate the RealFrac class so I can do truncate, round, etc., in the most natural way in the language. Implementing properFraction (which is in RealFrac) would not a problem at all, but implementing RealFrac requires implementing Real, which has the function toRational, which Haskell 98 says "returns the rational equivalent of its real argument with full precision" which isn't possible for this number type (which includes irrationals). I'd also like to implement approxRational since this can be done in a straightforward manner with my data type, but this appears to be just a library function in the Ratio library and not a function defined in a class, and is dependent on the toRational function which doesn't make sense for a data type that can represent irrational values exactly. So my questions are: 1) Am I understanding the Haskell numeric classes correctly by thinking that to define properFraction I also have to define (incorrectly in this case) the toRational function? 2) Is a literal reading of Haskell 98 necessary for toRational or can it just be approximate? (Seems like not, since there's approxRational, and no other way to indicate the desired accuracy for toRational.) 3) If I'm right about toRational requiring "full precision", why was implementing this made a requirement for implementing properFraction? 4) Why on earth is there a class called "Real" that requires the ability to convert to Rational with full precision, which can't be done with all real numbers? As an example, consider a data type that can represent a quadratic surd, e.g. (1, 5, 2) might mean (1 + (sqrt 5)) / 2. With this data type it's straightforward to implement the Num and Fractional classes and get full arithmetic operations +, -, *, /, etc. The properFraction function also makes sense: there's an integer portion equal to 1 in this case, and a fractional portion equal to (-1, 5, 2), exactly. So truncate, round, ceiling, and floor make sense (in RealFrac). But toRational can't be implemented with "full precision". With this example you can also see how approxRational is a perfectly good idea, and would be something likely to be needed, but this function isn't a class function designed to be implemented by custom data types. It seems to me (with my meager few days of Haskell experience) that approxRational should have been part of the Real class, and that toRational should be relegated the Ratio library instead. Or else, that the functions that are in RealFrac should be in the Fractional class instead. So I'm guessing there are some good reasons for having RealFrac in addition to Fractional that I'm not yet aware of. -- View this message in context: http://www.nabble.com/Why-does-the-class-called-%22Real%22-support-only-rati... Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

Yes, I'm afraid that you are understanding correctly. Annoying isn't it. It is well-known (among Haskell mathematicians at least) that the numeric type classes in the prelude are broken. Here's one proposal for a small step in the right direction: http://hackage.haskell.org/trac/haskell-prime/ticket/112 But it really needs a mathematician to sit down and sort it out properly.

DavidA-2 wrote:
Yes, I'm afraid that you are understanding correctly. Annoying isn't it.
It is well-known (among Haskell mathematicians at least) that the numeric type classes in the prelude are broken.
Here's one proposal for a small step in the right direction: http://hackage.haskell.org/trac/haskell-prime/ticket/112
But it really needs a mathematician to sit down and sort it out properly.
Yes, very annoying. If I ran into this so quickly it makes me wonder how it ended up this way. It also makes me wonder what else is broken, but at least it doesn't appear to be a problem with the language itself. So far Haskell has been a real eye-opener, as I've been programming for 26 years and haven't been exposed to functional programming before now. It's embarrassing to say, actually. -- View this message in context: http://www.nabble.com/Why-does-the-class-called-%22Real%22-support-only-rati... Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

On 6/4/07, DavidA
Yes, I'm afraid that you are understanding correctly. Annoying isn't it.
It is well-known (among Haskell mathematicians at least) that the numeric type classes in the prelude are broken.
A few days ago I found myself forced to write:
instance Floating Fixed where ...
where 'Fixed' is a fixed point arithmetic class! :-) When you find yourself having to make a type an instance of the complete 'opposite' class you know you have serious problems! -- Dan

On Mon, 4 Jun 2007, Dan Piponi wrote:
On 6/4/07, DavidA
wrote: Yes, I'm afraid that you are understanding correctly. Annoying isn't it.
It is well-known (among Haskell mathematicians at least) that the numeric type classes in the prelude are broken.
A few days ago I found myself forced to write:
instance Floating Fixed where ...
where 'Fixed' is a fixed point arithmetic class! :-)
When you find yourself having to make a type an instance of the complete 'opposite' class you know you have serious problems!
Indeed. The corresponding class is called Transcendental in NumericPrelude. (And FixedPoint is an instance of it.)

On Sun, 3 Jun 2007, bretm wrote:
I just got started learning Haskell a few days ago. I've implemented a numeric data type that can represent some irrational numbers exactly, and I'd like to instantiate the RealFrac class so I can do truncate, round, etc., in the most natural way in the language.
There are several things that are inconvenient in the numeric part of Haskell 98 Prelude. As always I suggest a look at alternative numeric class hierarchies, like NumericPrelude: http://www.haskell.org/haskellwiki/Applications_and_libraries/Mathematics#Ty... Is your approach more like symbolic calculation or more like a representation for computable reals? http://www.haskell.org/haskellwiki/Applications_and_libraries/Mathematics#Nu...
Implementing properFraction (which is in RealFrac) would not a problem at all, but implementing RealFrac requires implementing Real, which has the function toRational, which Haskell 98 says "returns the rational equivalent of its real argument with full precision" which isn't possible for this number type (which includes irrationals).
This obviously assumes, that all representations of reals in a computer must be actually rationals. But in Haskell with lazy evaluation this is not true: http://darcs.haskell.org/numericprelude/src/Number/Positional.hs
So my questions are: 1) Am I understanding the Haskell numeric classes correctly by thinking that to define properFraction I also have to define (incorrectly in this case) the toRational function? 2) Is a literal reading of Haskell 98 necessary for toRational or can it just be approximate? (Seems like not, since there's approxRational, and no other way to indicate the desired accuracy for toRational.)
In your case approximate would be the only possibility, I guess. Like computations with Float and Double are approximate.
As an example, consider a data type that can represent a quadratic surd, e.g. (1, 5, 2) might mean (1 + (sqrt 5)) / 2.
With NumericPrelude you can work with such numbers using polynomials modulo the "polynomial" (x^2-5). $ make ghci *Main> ResidueClass.concrete (polynomial [-5,0,1::Rational]) (polyResidueClass [1,1] / 2 * polyResidueClass[1,1] / 2) Polynomial.fromCoeffs [3 % 2,1 % 2] meaning (1 + sqrt 5) / 2 * (1 + sqrt 5) / 2 = (3 + sqrt 5) / 2

Awesomely complete response. Thank you. Henning Thielemann wrote:
There are several things that are inconvenient in the numeric part of Haskell 98 Prelude. As always I suggest a look at alternative numeric class hierarchies, like NumericPrelude:
http://www.haskell.org/haskellwiki/Applications_and_libraries/Mathematics#Ty...
I definitely will. Henning Thielemann wrote:
Is your approach more like symbolic calculation or more like a representation for computable reals?
http://www.haskell.org/haskellwiki/Applications_and_libraries/Mathematics#Nu...
Computable reals, specifically continued fraction representation. I know I'm reinventing the wheel here (I was using an OCaml implementation called ContFrac as a guide to the algorithms) but I'm just playing with this as a vehicle for learning Haskell. -- View this message in context: http://www.nabble.com/Why-does-the-class-called-%22Real%22-support-only-rati... Sent from the Haskell - Haskell-Cafe mailing list archive at Nabble.com.

On Mon, 4 Jun 2007, bretm wrote:
Henning Thielemann wrote:
Is your approach more like symbolic calculation or more like a representation for computable reals?
http://www.haskell.org/haskellwiki/Applications_and_libraries/Mathematics#Nu...
Computable reals, specifically continued fraction representation. I know I'm reinventing the wheel here
Jan Skibinski did it for Haskell, too.
(I was using an OCaml implementation called ContFrac as a guide to the algorithms) but I'm just playing with this as a vehicle for learning Haskell.
If you plan to use NumericPrelude, I'll glad to hear experiences about the usefulness of the NumericPrelude class hierarchy, and we could add it to that library.
participants (4)
-
bretm
-
Dan Piponi
-
DavidA
-
Henning Thielemann