    {-# LANGUAGE CPP #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    module Basement.Compat.Natural
        ( Natural
        , integerToNatural
        , naturalToInteger
        ) where

    #if MIN_VERSION_base(4,8,0)

    import Numeric.Natural
    import Prelude (Integer, abs, fromInteger, toInteger)

    #else

    import Prelude (Show(..),Eq,Ord,Enum,Num(..),Real(..),Integral(..),Integer,error,(<), (>), otherwise, toInteger)
    import Data.Bits
    import Data.Typeable

    newtype Natural = Natural Integer
        deriving (Eq,Ord,Enum,Typeable,Bits)

    instance Show Natural where
        show (Natural i) = show i

    -- re-create the buggy Num instance for Natural
    instance Num Natural where
        fromInteger n
            | n < 0     = error "natural should be positive: "
            | otherwise = Natural n
        (+) (Natural a) (Natural b) = Natural (a + b)
        (-) (Natural a) (Natural b)
            | r < 0     = error "natural should be positve"
            | otherwise = Natural (a - b)
          where r = (a - b)
        (*) (Natural a) (Natural b) = Natural (a * b)
        abs n = n
        negate n = n
        signum (Natural n)
            | n > 0     = 1
            | otherwise = 0

    instance Real Natural where
        toRational (Natural n) = toRational n

    instance Integral Natural where
        toInteger (Natural n) = n
        divMod (Natural n) (Natural e) = let (a,b) = n `quotRem` e in (Natural a, Natural b)
        quotRem (Natural n) (Natural e) = let (a,b) = n `quotRem` e in (Natural a, Natural b)
        quot (Natural n) (Natural e) = Natural (n `quot` e)
        rem (Natural n) (Natural e) = Natural (n `rem` e)
        div = quot
        mod = rem

    #endif

    integerToNatural :: Integer -> Natural
    integerToNatural i = fromInteger (abs i)

    naturalToInteger :: Natural -> Integer
    naturalToInteger n = toInteger n