-- | The implementations of all functions except for rem, quot, div, mod are -- supposed to be as non-strict as possible. module Data.Number.Int ( Int(..), pos ) where import Prelude hiding ( Int ) import Data.Number.Nat1 import Data.Number.Nat import Data.Ratio ( (%) ) -- | Integers data Int -- | A negative natural number = Neg Nat1 -- | A positive natural number or zero | Pos0 Nat deriving Eq pos :: Nat1 -> Int pos = Pos0 . Pos zero :: Int zero = Pos0 Zero instance Show Int where show (Neg n) = "-" ++ show n show (Pos0 n) = show n instance Read Int where readsPrec n = map (\(x,str) -> (toEnum x,str)) . readsPrec n instance Ord Int where compare (Neg _) (Pos0 _) = LT compare (Pos0 _) (Neg _) = GT compare (Pos0 m) (Pos0 n) = compare m n compare (Neg m) (Neg n) = compare n m x < y = cmpIntLT y x == GT x > y = cmpIntLT x y == GT x <= y = cmpIntLT x y == LT x >= y = cmpIntLT y x == LT cmpIntLT :: Int -> Int -> Ordering cmpIntLT (Neg _) (Pos0 _) = LT cmpIntLT (Pos0 _) (Neg _) = GT cmpIntLT (Pos0 m) (Pos0 n) = cmpNatLT m n cmpIntLT (Neg m) (Neg n) = invOrd (cmpNat1LT m n) instance Enum Int where succ (Pos0 n) = Pos0 (succ n) succ (Neg IHi) = zero succ (Neg n) = Neg (succ n) pred (Neg n) = Neg (pred n) pred (Pos0 Zero) = Neg IHi pred (Pos0 n) = Pos0 (pred n) toEnum = toInt fromEnum = fromInt instance Num Int where n + Pos0 Zero = n Neg m + Pos0 (Pos n) = n -^ m Pos0 Zero + n = n Pos0 (Pos m) + Neg n = m -^ n Pos0 m + Pos0 n = Pos0 (m+n) Neg m + Neg n = Neg (m+n) m - Neg n = m + pos n m - Pos0 Zero = m m - Pos0 (Pos n) = m + Neg n _ * Pos0 Zero = zero Pos0 Zero * _ = zero Neg m * Pos0 (Pos n) = Neg (m*n) Pos0 (Pos m) * Neg n = Neg (m*n) Neg m * Neg n = pos (m*n) Pos0 m * Pos0 n = Pos0 (m*n) negate (Neg n) = pos n negate n@(Pos0 Zero) = n negate (Pos0 (Pos n)) = Neg n signum (Neg _) = Neg IHi signum n@(Pos0 Zero) = n signum (Pos0 _) = pos IHi abs (Neg n) = pos n abs n = n fromInteger = toInt -- this implementation is least strict -- for example: I _|_ -^ O IHi = (Nat _|_) -- while the standard implementation yields _|_ in this case -- another solution would be to use another datatype ??? -- data Int = Neg NatO | Pos Nat (-^) :: Nat1 -> Nat1 -> Int x -^ y = case minus x y of Pos0 n -> Pos0 n Neg IHi -> zero Neg n -> Neg (pred n) -- minus x y yields x - y - 1 if x - y <= 0 -- x - y otherwise minus :: Nat1 -> Nat1 -> Int minus IHi y = Neg y minus x@(O _) IHi = pos (pred x) minus (I x) IHi = pos (O x) minus (O x) (O y) = incNeg (o (minus x y)) minus (I x) (I y) = incNeg (o (minus x y)) minus (O x) (I y) = decNeg (o (minus x y)) minus (I x) (O y) = decNeg (o (negate (minus y x))) o :: Int -> Int o (Neg n) = Neg (O n) o (Pos0 n) = Pos0 (case n of Zero -> Zero Pos m -> Pos (O m)) incNeg :: Int -> Int incNeg (Neg n) = Neg (pred n) incNeg (Pos0 n) = Pos0 n decNeg :: Int -> Int decNeg (Neg n) = Neg n decNeg (Pos0 n) = Pos0 (pred n) instance Integral Int where quotRem (Neg m) (Neg n) = (Pos0 q,neg r) where (q,r) = quotRem (Pos m) (Pos n) quotRem (Neg m) (Pos0 n) = (neg q,neg r) where (q,r) = quotRem (Pos m) n quotRem (Pos0 m) (Neg n) = (neg q,Pos0 r) where (q,r) = quotRem m (Pos n) quotRem (Pos0 m) (Pos0 n) = (Pos0 q,Pos0 r) where (q,r) = quotRem m n toInteger = fromInt neg :: Nat -> Int neg Zero = zero neg (Pos n) = Neg n fromInt :: Num n => Int -> n fromInt (Neg n) = -fromNat1 n fromInt (Pos0 n) = fromNat n toInt :: (Integral n,Num n) => n -> Int toInt n | n<0 = Neg (toNat1 (-n)) | otherwise = Pos0 (toNat n) instance Real Int where toRational n = toInteger n % 1