Inspired by this article about natural numbers from first principles in swift I implemented integers from scratch in Haskell.
Besides obviously being extremely inefficient, is this code idiomatic Haskell?
import Data.List
import GHC.Real
data ℤ = Pred ℤ | Zero | Succ ℤ
toNat = toEnum :: Int -> ℤ
fromNat = fromEnum :: ℤ -> Int
toInteger' :: ℤ -> Integer
toInteger' Zero = 0
toInteger' (Succ n) = toInteger' n + 1
toInteger' (Pred n) = toInteger' n - 1
instance Show ℤ where
show = ((++) "Nat: ") . show . toInteger'
data SimpleNat = MinusOne | One deriving (Eq, Ord, Show)
toList :: ℤ -> [SimpleNat]
toList Zero = []
toList (Succ n) = One : toList n
toList (Pred n) = MinusOne : toList n
fromList :: [SimpleNat] -> ℤ
fromList [] = Zero
fromList (One:xs) = Succ (fromList xs)
fromList (MinusOne:xs) = Pred (fromList xs)
normaliseList :: [SimpleNat] -> [SimpleNat]
normaliseList xs = normaliseSorted $ sort xs
where normaliseSorted xs = map fst filtered
filtered = filter (uncurry (==)) $ zip xs (reverse xs)
normalise :: ℤ -> ℤ
normalise = fromList . normaliseList . toList
instance Enum ℤ where
succ (Pred n) = n
succ n = Succ n
pred (Succ n) = n
pred n = Pred n
toEnum n | n < 0 = Pred $ toEnum (n+1)
| n > 0 = Succ $ toEnum (n-1)
| otherwise = Zero
fromEnum Zero = 0
fromEnum (Succ n) = fromEnum n + 1
fromEnum (Pred n) = fromEnum n - 1
instance Num ℤ where
Zero + n = n
n + Zero = n
(Succ n) + m = Succ (n + m)
(Pred n) + m = Pred (n + m)
abs n = abs' $ normalise n
where abs' (Pred n) = Succ (abs' n)
abs' n = n
signum n = signum' $ normalise n
where signum' Zero = Zero
signum' (Succ n) = Succ Zero
signum' (Pred n) = Pred Zero
negate n = negate' $ normalise n
where negate' Zero = Zero
negate' (Succ n) = Pred (negate' n)
negate' (Pred n) = Succ (negate' n)
fromInteger n | n < 0 = Pred $ fromInteger (n+1)
| n > 0 = Succ $ fromInteger (n-1)
| otherwise = Zero
Zero * _ = Zero
_ * Zero = Zero
(Succ n) * m = n*m + m
(Pred n) * m = n*m - m
instance Eq ℤ where
n == m = normalise n `eq` normalise m
where Zero `eq` Zero = True
(Succ n) `eq` (Succ m) = n `eq` m
(Pred n) `eq` (Pred m) = n `eq` m
_ `eq` _ = False
instance Ord ℤ where
a `compare` b = normalise a `comp` normalise b
where Zero `comp` Zero = EQ
Zero `comp` (Succ _) = LT
Zero `comp` (Pred _) = GT
(Succ _) `comp` Zero = GT
(Succ _) `comp` (Pred _) = GT
(Pred _) `comp` Zero = LT
(Pred _) `comp` (Succ _) = LT
(Succ n) `comp` (Succ m) = n `comp` m
(Pred n) `comp` (Pred m) = n `comp` m
instance Real ℤ where
toRational n = toInteger' n % 1
instance Integral ℤ where
toInteger = toInteger'
quotRem _ Zero = error "divide by zero"
quotRem Zero _ = (Zero, Zero)
quotRem n d | n == d = (Succ Zero,0)
| n < d = (Zero, n)
| otherwise = (Succ (fst foo), snd foo)
where foo = (n-d) `quotRem` d