{-# OPTIONS_GHC -Wall #-}
module NumHask.Data.Integral
( Integral(..)
, ToInteger(..)
, FromInteger(..)
, fromIntegral
, even
, odd
, (^)
, (^^)
)
where
import Data.Int (Int8, Int16, Int32, Int64)
import Data.Word (Word, Word8, Word16, Word32, Word64)
import GHC.Natural (Natural(..))
import NumHask.Algebra.Abstract.Additive
import NumHask.Algebra.Abstract.Multiplicative
import NumHask.Algebra.Abstract.Ring
import Prelude (Double, Float, Int, Integer, (.), fst, snd)
import qualified Prelude as P
class (Distributive a) =>
Integral a where
infixl 7 `div`, `mod`
div :: a -> a -> a
div a1 a2 = fst (divMod a1 a2)
mod :: a -> a -> a
mod a1 a2 = snd (divMod a1 a2)
divMod :: a -> a -> (a, a)
quot :: a -> a -> a
quot a1 a2 = fst (quotRem a1 a2)
rem :: a -> a -> a
rem a1 a2 = snd (quotRem a1 a2)
quotRem :: a -> a -> (a, a)
instance Integral Int where
divMod = P.divMod
quotRem = P.quotRem
instance Integral Integer where
divMod = P.divMod
quotRem = P.quotRem
instance Integral Natural where
divMod = P.divMod
quotRem = P.quotRem
instance Integral Int8 where
divMod = P.divMod
quotRem = P.quotRem
instance Integral Int16 where
divMod = P.divMod
quotRem = P.quotRem
instance Integral Int32 where
divMod = P.divMod
quotRem = P.quotRem
instance Integral Int64 where
divMod = P.divMod
quotRem = P.quotRem
instance Integral Word where
divMod = P.divMod
quotRem = P.quotRem
instance Integral Word8 where
divMod = P.divMod
quotRem = P.quotRem
instance Integral Word16 where
divMod = P.divMod
quotRem = P.quotRem
instance Integral Word32 where
divMod = P.divMod
quotRem = P.quotRem
instance Integral Word64 where
divMod = P.divMod
quotRem = P.quotRem
instance Integral b => Integral (a -> b) where
div f f' a = f a `div` f' a
mod f f' a = f a `mod` f' a
divMod f f' = (\a -> fst (f a `divMod` f' a), \a -> snd (f a `divMod` f' a))
quot f f' a = f a `mod` f' a
rem f f' a = f a `mod` f' a
quotRem f f' = (\a -> fst (f a `quotRem` f' a), \a -> snd (f a `quotRem` f' a))
class ToInteger a where
toInteger :: a -> Integer
instance ToInteger Int where
toInteger = P.toInteger
instance ToInteger Integer where
toInteger = P.toInteger
instance ToInteger Natural where
toInteger = P.toInteger
instance ToInteger Int8 where
toInteger = P.toInteger
instance ToInteger Int16 where
toInteger = P.toInteger
instance ToInteger Int32 where
toInteger = P.toInteger
instance ToInteger Int64 where
toInteger = P.toInteger
instance ToInteger Word where
toInteger = P.toInteger
instance ToInteger Word8 where
toInteger = P.toInteger
instance ToInteger Word16 where
toInteger = P.toInteger
instance ToInteger Word32 where
toInteger = P.toInteger
instance ToInteger Word64 where
toInteger = P.toInteger
class FromInteger a where
fromInteger :: Integer -> a
instance FromInteger b => FromInteger (a -> b) where
fromInteger i _ = fromInteger i
fromIntegral :: (ToInteger a, FromInteger b) => a -> b
fromIntegral = fromInteger . toInteger
instance FromInteger Double where
fromInteger = P.fromInteger
instance FromInteger Float where
fromInteger = P.fromInteger
instance FromInteger Int where
fromInteger = P.fromInteger
instance FromInteger Integer where
fromInteger = P.fromInteger
instance FromInteger Natural where
fromInteger = P.fromInteger
instance FromInteger Int8 where
fromInteger = P.fromInteger
instance FromInteger Int16 where
fromInteger = P.fromInteger
instance FromInteger Int32 where
fromInteger = P.fromInteger
instance FromInteger Int64 where
fromInteger = P.fromInteger
instance FromInteger Word where
fromInteger = P.fromInteger
instance FromInteger Word8 where
fromInteger = P.fromInteger
instance FromInteger Word16 where
fromInteger = P.fromInteger
instance FromInteger Word32 where
fromInteger = P.fromInteger
instance FromInteger Word64 where
fromInteger = P.fromInteger
even :: (P.Eq a, Integral a) => a -> P.Bool
even n = n `rem` (one + one) P.== zero
odd :: (P.Eq a, Integral a) => a -> P.Bool
odd = P.not . even
(^)
:: (P.Ord b, Multiplicative a, Integral b)
=> a
-> b
-> a
x0 ^ y0
| y0 P.< zero = P.undefined
|
y0 P.== zero = one
| P.otherwise = f x0 y0
where
f x y
| even y = f (x * x) (y `quot` two)
| y P.== one = x
| P.otherwise = g (x * x) (y `quot` two) x
g x y z
| even y = g (x * x) (y `quot` two) z
| y P.== one = x * z
| P.otherwise = g (x * x) (y `quot` two) (x * z)
(^^)
:: (Divisive a, Subtractive b, Integral b, P.Ord b) => a -> b -> a
(^^) x n = if n P.>= zero then x ^ n else recip (x ^ negate n)