-- | Class instances for the continued fraction datatype {-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-} module Data.Number.Instances where import Data.Number.Types import Data.Number.Internal -- | transform a number applying a function ('Nat' -> 'Nat') to each -- number preserving the sign. instance Functor Continued where fmap _ E = E fmap f (M x) = M (fmap f x) fmap f (x:|xs) = f x :| fmap f xs -- | Basic Foldable instance implemented exactly as a list. instance Foldable Continued where foldr f z E = z foldr f z (M x) = foldr f z x foldr f z (x:|xs) = f x (foldr f z xs) -- | Same as above. instance Traversable Continued where traverse _ E = pure E traverse f (M x) = traverse f x traverse f (x:|xs) = (:|) <$> f x <*> traverse f xs -- | The sign is given by the first number of the fraction. -- Other number are always considered positive. instance Num Number where (+) = operator (0, 1, 1, 0, 1, 0, 0, 0) (-) = operator (0, 1, -1, 0, 1, 0, 0, 0) (*) = operator (0, 0, 0, 1, 1, 0, 0, 0) abs (M x) = x abs x = x negate (M x) = x negate x = M x fromInteger = toNumber . fromIntegral signum E = 0 signum (M _) = -1 signum _ = 1 -- | Allows conversion to a rational instance Real Number where toRational = fromNumber -- | Allows division between 'Number's and conversion from a rational instance Fractional Number where (/) = operator (0, 1, 0, 0, 0, 0, 1, 0) fromRational = toNumber -- Helpers -- -- | Convert a 'Number' into a 'RealFrac' number fromNumber :: RealFrac a => Number -> a fromNumber E = 0 fromNumber (M x) = negate (fromNumber x) fromNumber (x :| E) = fromIntegral x fromNumber (x :| xs) = fromIntegral x + 1 / (fromNumber xs) -- | Convert a 'RealFrac' number into a 'Number' toNumber :: (Show a, RealFrac a) => a -> Number toNumber 0 = E toNumber x0 | x0 < 0 = M (n :| toNumber x1) | otherwise = n :| toNumber x1 where (n,f) = properFraction (abs x0) x1 | f < 1e-6 = 0 | otherwise = 1/f