{-| 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