{-|
The Natural module attempts to provide a representation of natural numbers
(non-positive integers) which behave as much as possible like normal Integers.
All calculations which would normally return a negative number result in an
Indeterminate value. Once a Natural becomes Indeterminate, it will remain
indeterminate in subsequent calculations. Such a calculation has, in effect,
been errored-out in a safe manner.
This is not a type-level representation of naturals as in some packages. It is
basically a wrapper around the Integer type, using pattern-based rewriting.
Naturals are created with the safe constructors natural or indeterm. Note that
for practical reasons Indeterminate values are considered equal, which allows
easy detection of an errored-out calculation via comparison.
Feel free to send me an e-mail if you find the package useful, or if you have
any suggestions or code to share.
-}
module Data.Natural ( Natural()
, natural
, indeterm
) where
import Data.Ratio ((%))
data Natural = Natural Integer | Indeterminate deriving (Show)
{-|
Constructs a Natural number, which is defined here as all non-negative
integers, including zero. Passing in a negative integer will result in an
Indeterminate value.
>>> natural 10
Natural 10
>>> natural 0
Natural 0
>>> natural (-1)
Indeterminate
-}
natural :: Integer -> Natural
natural n | n < 0 = Indeterminate
natural n = Natural n
{-|
Constructs a Natural number with an Indeterminate value. Useful for detecting
an Indeterminate value through comparison.
>>> natural 3 - natural 4 == indeterm
True
-}
indeterm :: Natural
indeterm = Indeterminate
instance Eq Natural where
-- equality of Indeterminate values is necessary to satisfy signum law
(==) Indeterminate Indeterminate = True
(==) Indeterminate _ = False
(==) _ Indeterminate = False
(==) (Natural a) (Natural b) = a == b
instance Num Natural where
Indeterminate + _ = Indeterminate
_ + Indeterminate = Indeterminate
(Natural a) + (Natural b) = Natural (a+b)
Indeterminate - _ = Indeterminate
_ - Indeterminate = Indeterminate
(Natural a) - (Natural b) | a < b = Indeterminate
| otherwise = Natural (a-b)
Indeterminate * _ = Indeterminate
_ * Indeterminate = Indeterminate
(Natural a) * (Natural b) = Natural (a*b)
abs Indeterminate = Indeterminate
abs (Natural a) = Natural a
signum Indeterminate = Indeterminate
signum (Natural 0) = Natural 0
signum (Natural _) = Natural 1
fromInteger = natural
instance Ord Natural where
compare Indeterminate Indeterminate = EQ
compare _ Indeterminate = GT
compare Indeterminate _ = LT
compare (Natural a) (Natural b) = compare a b
instance Real Natural where
toRational Indeterminate = error $ "Natural of Indeterminate value cannot be"
++ " converted to a Rational"
toRational (Natural a) = a % 1
instance Enum Natural where
succ Indeterminate = Indeterminate
succ (Natural a) = Natural (a+1)
pred Indeterminate = Indeterminate
pred (Natural 0) = Indeterminate
pred (Natural a) = Natural (a-1)
toEnum a = natural (toInteger a)
fromEnum Indeterminate = error $ "Natural of Indeterminant value cannot be"
++ " converted to an Int"
fromEnum (Natural a) = fromInteger a :: Int
instance Integral Natural where
quotRem Indeterminate _ = (Indeterminate, Indeterminate)
quotRem _ Indeterminate = (Indeterminate, Indeterminate)
quotRem (Natural a) (Natural b) = ( natural $ quot a b
, natural $ rem a b )
toInteger Indeterminate = error $ "Natural of Indeterminate value cannot be"
++ " converted to an Integer"
toInteger (Natural a) = a