module Numeric.Peano where
import Data.Ratio ((%))
data Nat = Z | S Nat deriving (Show)
data Sign = Pos | Neg deriving (Show, Eq, Ord, Enum, Read, Bounded)
data Whole = Whole Nat Sign
class Enum a => Peano a where
isZero :: a -> Bool
infinity :: a
fromPeano :: a -> Integer
decr :: a -> a
isSucc :: Peano n => n -> Bool
isSucc = not . isZero
instance Peano Nat where
isZero Z = True
isZero _ = False
infinity = S infinity
fromPeano Z = 0
fromPeano (S n) = succ $ fromPeano n
decr = pred
instance Peano Whole where
isZero (Whole n _) = isZero n
infinity = Whole infinity Pos
fromPeano (Whole n Pos) = fromPeano n
fromPeano (Whole n Neg) = negate $ fromPeano n
decr (Whole n s) = Whole (pred n) s
takeNat :: (Num a, Enum a, Ord a, Peano n) => a -> n -> (a, n)
takeNat = takeNat' 0
where
takeNat' c i n | i <= 0 = (c, n)
| isZero n = (c, n)
| otherwise = takeNat' (succ c) (pred i) (decr n)
instance Bounded Nat where
minBound = Z
maxBound = infinity
instance Bounded Whole where
minBound = Whole infinity Neg
maxBound = infinity
instance Enum Nat where
toEnum = fromInteger . fromIntegral
fromEnum = fromInteger . fromPeano
succ = S
pred Z = Z
pred (S n) = n
instance Enum Whole where
toEnum i | i < 0 = Whole (toEnum i) Neg
| otherwise = Whole (toEnum i) Pos
fromEnum = fromInteger . fromPeano
succ (Whole (S n) Neg) = Whole n Neg
succ (Whole n Pos) = Whole (S n) Pos
succ (Whole Z _) = Whole (S Z) Pos
pred (Whole (S n) Pos) = Whole n Pos
pred (Whole n Neg) = Whole (S n) Neg
pred (Whole Z _) = Whole (S Z) Neg
instance Num Nat where
(+) Z n = n
(+) n Z = n
(+) (S n) (S m) = S $ S $ (+) n m
(*) Z n = Z
(*) n Z = Z
(*) (S n) (S m) = S Z + n + m + (n * m)
abs = id
signum _ = S Z
fromInteger i | i <= 0 = Z
| otherwise = S $ fromInteger $ i 1
() Z n = Z
() n Z = n
() (S n) (S m) = n m
instance Num Whole where
(+) (Whole n Pos) (Whole m Pos) = Whole (n+m) Pos
(+) (Whole n Neg) (Whole m Neg) = Whole (n+m) Neg
(+) (Whole n Pos) (Whole m Neg) | n >= m = Whole (nm) Pos
| otherwise = Whole (mn) Neg
(+) (Whole n Neg) (Whole m Pos) = Whole m Pos + Whole n Neg
(*) (Whole n s) (Whole m t) | s == t = Whole (n*m) Pos
| otherwise = Whole (n*m) Neg
() n (Whole m Neg) = n + (Whole m Pos)
() n (Whole m Pos) = n + (Whole m Neg)
abs (Whole n s) = Whole n Pos
signum (Whole Z _) = Whole Z Pos
signum (Whole _ Pos) = Whole (S Z) Pos
signum (Whole _ Neg) = Whole (S Z) Neg
fromInteger i | i < 0 = Whole (fromInteger $ negate i) Neg
| otherwise = Whole (fromInteger i) Pos
instance Eq Nat where
(==) Z Z = True
(==) Z (S _) = False
(==) (S _) Z = False
(==) (S n) (S m) = n == m
instance Eq Whole where
(==) (Whole Z _) (Whole Z _) = True
(==) (Whole n s) (Whole m t) = s == t && n == m
instance Ord Nat where
compare Z Z = EQ
compare Z (S _) = LT
compare (S _) Z = GT
compare (S n) (S m) = compare n m
instance Ord Whole where
compare (Whole Z _) (Whole Z _) = EQ
compare (Whole _ Neg) (Whole _ Pos) = LT
compare (Whole _ Pos) (Whole _ Neg) = GT
compare (Whole n Pos) (Whole m Pos) = compare n m
compare (Whole n Neg) (Whole m Neg) = compare m n
natLength :: [a] -> Nat
natLength [] = Z
natLength (_:xs) = S $ natLength xs
instance Real Nat where
toRational = flip (%) 1 . fromPeano
instance Integral Nat where
quotRem _ Z = error "divide by zero"
quotRem n (S m) = quotRem' Z n (S m)
where
quotRem' q n m | n >= m = quotRem' (S q) (nm) m
| otherwise = (q,n)
divMod = quotRem
toInteger = fromPeano