{-# LANGUAGE ExtendedDefaultRules #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -Wall #-} -- | Integral domains module NumHask.Algebra.Integral ( -- * Integral Integral(..) , ToInteger(..) , FromInteger(..) , fromIntegral ) where import qualified Protolude as P import Protolude (Double, Float, Int, Integer, Functor(..), ($), (.), Foldable(..), fst, snd, foldr, const, Ord(..)) import Data.Functor.Rep import NumHask.Algebra.Additive import NumHask.Algebra.Multiplicative import NumHask.Algebra.Ring -- | Integral -- -- > b == zero || b * (a `div` b) + (a `mod` b) == a -- class (Ring a) => Integral a where infixl 7 `div`, `mod` -- | truncates towards negative infinity 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) instance Integral Int where divMod = P.divMod instance Integral Integer where divMod = P.divMod instance (Representable r, Integral a) => Integral (r a) where divMod a b = (d,m) where x = liftR2 divMod a b d = fmap fst x m = fmap snd x -- | toInteger and fromInteger as per the base 'Num' instance is problematic for numbers with a 'Basis' class (Integral a) => ToInteger a where toInteger :: a -> Integer -- | fromInteger class (Ring a) => FromInteger a where fromInteger :: Integer -> a fromInteger = slowFromInteger slowFromInteger :: (Ring r) => Integer -> r slowFromInteger i = if i > zero then foldr (+) zero $ fmap (const one) [one..i] else negate $ foldr (+) zero $ fmap (const one) [one..negate i] -- | This splitting away of fromInteger from the 'Ring' instance tends to increase constraint boier-plate 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 ToInteger Int where toInteger = P.toInteger instance ToInteger Integer where toInteger = P.toInteger