module Unary where

data Unary = Z | S Unary
    deriving (Eq)

instance Num Unary where
    Z     + y = y
    x     + Z = x
    (S x) + y = S (x `rightPlus` y)

    abs x = x
    signum Z = Z
    signum (S x) = S Z
    fromInteger x | 0 == x = Z
                  | 0 <= x = S (fromInteger (x-1))
                  | otherwise = unaryUnderflow

    -- | Multiplication. Discouraged because slow.
    Z * y = Z
    x * Z = Z
    (S x) * y = y + (x * y)

unaryUnderflow = error "unary represents positive integers only"

instance Ord Unary where
    min Z y = Z
    min x Z = Z
    min (S x) (S y) = S (min x y)
    x < Z = False
    Z < S y = True
    S x < S y = x < y

instance Show Unary where
    show x = show (toInteger x)

instance Enum Unary where
    succ x = S x
    pred (S x) = x
    pred Z = error "No pred of Z"
    toEnum x | 0 <= x = foldr (const S) Z [1..x]
             | x < 0 = unaryUnderflow
    fromEnum Z = 0
    fromEnum (S x) = 1 + fromEnum x

instance Real Unary where
    toRational x = error "toRational undefined"

instance Integral Unary where
    toInteger Z = 0
    toInteger (S x) = 1 + toInteger x
    quotRem x y = let (q,r) = (quotRem (toInteger x) (toInteger y)) in
                  (fromInteger q, fromInteger r)

-- | Right-recursive version of (+), to balance the recursion.
rightPlus :: Unary -> Unary -> Unary
rightPlus Z     y = y
rightPlus x     Z = x
rightPlus x (S y) = S (x + y)