module Data.Number.NatO
(
NatO(..),
cmpNatOLT, fromNatO, toNatO,
length, take, drop, replicate,
lengthNum, takeNum, dropNum, replicateNum
) where
import Prelude hiding ( length, take, drop, replicate )
import Data.Number.Nat
import Data.Ratio ( (%) )
data NatO
= Zero
| Nat Nat
deriving Eq
instance Show NatO where
show Zero = "0"
show (Nat n) = show n
instance Read NatO where
readsPrec n = map (\(x,str) -> (toEnum x,str)) . readsPrec n
instance Ord NatO where
compare Zero Zero = EQ
compare Zero _ = LT
compare _ Zero = GT
compare (Nat m) (Nat n) = compare m n
x < y = cmpNatOLT y x == GT
x > y = cmpNatOLT x y == GT
x <= y = cmpNatOLT x y == LT
x >= y = cmpNatOLT y x == LT
cmpNatOLT :: NatO -> NatO -> Ordering
cmpNatOLT Zero _ = LT
cmpNatOLT _ Zero = GT
cmpNatOLT (Nat m) (Nat n) = cmpNatLT m n
instance Enum NatO where
succ = Nat . succ'
where
succ' Zero = IHi
succ' (Nat n) = succ n
pred Zero = error "predecessor of Zero"
pred (Nat IHi) = Zero
pred (Nat n) = Nat (pred n)
toEnum = toNatO
fromEnum = fromNatO
instance Num NatO where
Zero + n = n
n + Zero = n
Nat m + Nat n = Nat (m+n)
Zero Nat _ = error "negative result in (-)"
n Zero = n
Nat m Nat n = pred (Nat (minusNat m n))
Zero * _ = Zero
_ * Zero = Zero
Nat m * Nat n = Nat (m*n)
negate Zero = Zero
negate _ = error "negative result in negate"
signum Zero = Zero
signum (Nat _) = Nat IHi
abs = id
fromInteger = toNatO
instance Integral NatO where
div m n = fst $ divmodNatO m n
mod m n = snd $ divmodNatO m n
quotRem = divmodNatO
toInteger = fromNatO
fromNatO :: Num n => NatO -> n
fromNatO Zero = 0
fromNatO (Nat n) = fromNat n
toNatO :: (Integral n,Num n) => n -> NatO
toNatO n
| n<0 = error "negative argument in fromInteger"
| n==0 = Zero
| otherwise = Nat (toNat n)
instance Real NatO where
toRational n = toInteger n % 1
divmodNatO :: NatO -> NatO -> (NatO,NatO)
divmodNatO _ Zero = error "divide by zero"
divmodNatO x y = divmodNatO' x y
divmodNatO' :: NatO -> NatO -> (NatO,NatO)
divmodNatO' x y
| x<y = (Zero,x)
| otherwise = (succ q,r)
where
(q,r) = divmodNatO' (xy) y
length :: [a] -> NatO
length [] = Zero
length (_:xs) = succ (length xs)
take :: NatO -> [a] -> [a]
take Zero _ = []
take _ [] = []
take n (x:xs) = x:take (pred n) xs
drop :: NatO -> [a] -> [a]
drop Zero xs = xs
drop _ [] = []
drop n (_:xs) = drop (pred n) xs
replicate :: NatO -> a -> [a]
replicate n = take n . repeat
lengthNum :: (Enum n,Num n) => [a] -> n
lengthNum [] = 0
lengthNum (_:xs) = succ (lengthNum xs)
takeNum :: (Enum n,Num n) => n -> [a] -> [a]
takeNum n l
| n==0 = []
| otherwise = takeNum' l
where
takeNum' [] = []
takeNum' (x:xs) = x:takeNum (pred n) xs
dropNum :: (Enum n,Num n) => n -> [a] -> [a]
dropNum n l
| n==0 = l
| otherwise = dropNum' l
where
dropNum' [] = []
dropNum' (_:xs) = dropNum (pred n) xs
replicateNum :: (Enum n,Num n) => n -> a -> [a]
replicateNum n = takeNum n . repeat