{-# LANGUAGE CPP, DeriveDataTypeable #-}
{-# OPTIONS_GHC -Wall -fwarn-tabs #-}
module Data.Number.Nat
( Nat()
, fromNat
, toNat
, unsafeNat
, MaxNat(..)
) where
#if __GLASGOW_HASKELL__ < 710
import Data.Monoid (Monoid(..))
#endif
#if !(MIN_VERSION_base(4,11,0))
import Data.Semigroup
#endif
import Data.Data (Data, Typeable)
newtype Nat = Nat Int
deriving (Eq, Ord, Show, Data, Typeable)
instance Read Nat where
readsPrec d =
readParen (d > 10) $ \s0 -> do
("Nat", s1) <- lex s0
(i, s2) <- readsPrec 11 s1
maybe [] (\n -> [(n,s2)]) (toNat i)
fromNat :: Nat -> Int
fromNat (Nat i) = i
{-# INLINE fromNat #-}
toNat :: Int -> Maybe Nat
toNat x
| x < 0 = Nothing
| otherwise = Just (Nat x)
{-# INLINE toNat #-}
unsafeNat :: Int -> Nat
unsafeNat x
| x < 0 = error _errmsg_unsafeNat
| otherwise = Nat x
{-# INLINE unsafeNat #-}
instance Num Nat where
Nat i + Nat j = Nat (i + j)
Nat i * Nat j = Nat (i * j)
Nat i - Nat j
| i >= j = Nat (i - j)
| otherwise = error _errmsg_subtraction
negate _ = error _errmsg_negate
abs n = n
signum _ = Nat 1
fromInteger i
| i >= 0 && n >= 0 = Nat n
| otherwise = error _errmsg_fromInteger
where
n :: Int
n = fromInteger i
{-# INLINE (+) #-}
{-# INLINE (*) #-}
{-# INLINE (-) #-}
{-# INLINE negate #-}
{-# INLINE abs #-}
{-# INLINE signum #-}
{-# INLINE fromInteger #-}
instance Enum Nat where
succ (Nat i) = if i /= maxBound then Nat (i+1) else error _errmsg_succ
pred (Nat i) = if i /= 0 then Nat (i-1) else error _errmsg_pred
toEnum n = if n >= 0 then Nat n else error _errmsg_toEnum
fromEnum (Nat i) = i
enumFrom (Nat i) = map Nat (enumFrom i)
enumFromThen (Nat i) (Nat j) = map Nat (enumFromThen i j)
enumFromTo (Nat i) (Nat k) = map Nat (enumFromTo i k)
enumFromThenTo (Nat i) (Nat j) (Nat k) = map Nat (enumFromThenTo i j k)
{-# INLINE succ #-}
{-# INLINE pred #-}
{-# INLINE toEnum #-}
{-# INLINE fromEnum #-}
{-# INLINE enumFrom #-}
{-# INLINE enumFromThen #-}
{-# INLINE enumFromTo #-}
{-# INLINE enumFromThenTo #-}
instance Real Nat where
toRational (Nat i) = toRational i
{-# INLINE toRational #-}
instance Integral Nat where
quot (Nat i) (Nat j) = Nat (quot i j)
rem (Nat i) (Nat j) = Nat (rem i j)
quotRem (Nat i) (Nat j) = case quotRem i j of (q,r) -> (Nat q, Nat r)
div = quot
mod = rem
divMod = quotRem
toInteger (Nat i) = toInteger i
{-# INLINE quot #-}
{-# INLINE rem #-}
{-# INLINE div #-}
{-# INLINE mod #-}
{-# INLINE quotRem #-}
{-# INLINE divMod #-}
{-# INLINE toInteger #-}
newtype MaxNat = MaxNat { unMaxNat :: Nat }
instance Semigroup MaxNat where
MaxNat m <> MaxNat n = MaxNat (max m n)
instance Monoid MaxNat where
mempty = MaxNat 0
#if !(MIN_VERSION_base(4,11,0))
mappend = (<>)
#endif
_errmsg_unsafeNat, _errmsg_subtraction, _errmsg_negate, _errmsg_fromInteger, _errmsg_succ, _errmsg_pred, _errmsg_toEnum
:: String
_errmsg_unsafeNat = "unsafeNat: negative input"
_errmsg_subtraction = "(-)@Nat: Num is a bad abstraction"
_errmsg_negate = "negate@Nat: Num is a bad abstraction"
_errmsg_fromInteger = "fromInteger@Nat: Num is a bad abstraction"
_errmsg_succ = "succ@Nat: No successor of the maxBound"
_errmsg_pred = "pred@Nat: No predecessor of zero"
_errmsg_toEnum = "toEnum@Nat: negative input"
{-# NOINLINE _errmsg_unsafeNat #-}
{-# NOINLINE _errmsg_subtraction #-}
{-# NOINLINE _errmsg_negate #-}
{-# NOINLINE _errmsg_fromInteger #-}
{-# NOINLINE _errmsg_succ #-}
{-# NOINLINE _errmsg_pred #-}
{-# NOINLINE _errmsg_toEnum #-}