Now, here's Lennart's code (which works)
\begin{code}
-{-# SPECIALISE fromRat ::
- Rational -> Double,
- Rational -> Float #-}
+{-# SPECIALISE fromRat :: Rational -> Double,
+ Rational -> Float #-}
fromRat :: (RealFloat a) => Rational -> a
-fromRat x
- | x == 0 = encodeFloat 0 0 -- Handle exceptional cases
- | x < 0 = - fromRat' (-x) -- first.
- | otherwise = fromRat' x
+
+-- Deal with special cases first, delegating the real work to fromRat'
+fromRat (n :% 0) | n > 0 = 1/0 -- +Infinity
+ | n == 0 = 0/0 -- NaN
+ | n < 0 = -1/0 -- -Infinity
+
+fromRat (n :% d) | n > 0 = fromRat' (n :% d)
+ | n == 0 = encodeFloat 0 0 -- Zero
+ | n < 0 = - fromRat' ((-n) :% d)
-- Conversion process:
-- Scale the rational number by the RealFloat base until
-- a first guess of the exponent.
fromRat' :: (RealFloat a) => Rational -> a
+-- Invariant: argument is strictly positive
fromRat' x = r
where b = floatRadix r
p = floatDigits r
\begin{code}
data (Integral a) => Ratio a = !a :% !a deriving (Eq)
type Rational = Ratio Integer
+
+infinity, notANumber :: Rational
+infinity = 1 :% 0
+notANumber = 0 :% 0
+
+-- Use :%, not % for Inf/NaN; the latter would
+-- immediately lead to a runtime error, because it normalises.
\end{code}
isSpace, isAlpha, isAlphaNum,
isOctDigit, isHexDigit, toUpper )
import GHC.Real( Ratio(..), Integral, Rational, (%), fromIntegral, fromRational,
- toInteger, (^), (^^) )
+ toInteger, (^), (^^), infinity, notANumber )
import GHC.Float( Float, Double )
import GHC.List
import GHC.Show( ShowS, shows )
-- ---------------------------------------------------------------------------
-- Lexing numbers
-infinity, notANumber :: Rational
-infinity = 1 :% 0
-notANumber = 0 :% 0
-
--- Use :%, not % for Inf/NaN, the latter would
--- immediately lead to a runtime error.
---
--- Note that
--- isInfinite (read "Infinity" :: Float)
--- or
--- isInfinite (fromRational (1 :% 0))
--- still don't work, because fromRational is not OK for those cases.
---
--- The whole Infinity/NaN story is a bit murky to me
-
type Base = Int
type Digits = [Int]