
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