{-# LANGUAGE NoImplicitPrelude #-} module Number.ResidueClass.Reader where import qualified Number.ResidueClass as Res import qualified Algebra.PrincipalIdealDomain as PID import qualified Algebra.IntegralDomain as Integral import qualified Algebra.Ring as Ring import qualified Algebra.Additive as Additive import PreludeBase import NumericPrelude import Control.Monad (liftM2, liftM4) -- import Control.Monad.Reader (MonadReader) import qualified Prelude as P import qualified NumericPrelude as NP {- | T is a Reader monad but does not need functional dependencies like that from the Monad Template Library. -} newtype T a b = Cons {toFunc :: a -> b} concrete :: a -> T a b -> b concrete m (Cons r) = r m fromRepresentative :: (Integral.C a) => a -> T a a fromRepresentative = Cons . mod getZero :: (Additive.C a) => T a a getZero = Cons $ const Additive.zero getOne :: (Ring.C a) => T a a getOne = Cons $ const NP.one fromInteger :: (Integral.C a) => Integer -> T a a fromInteger = fromRepresentative . NP.fromInteger instance Monad (T a) where (Cons x) >>= y = Cons (\r -> toFunc (y (x r)) r) return = Cons . const getAdd :: Integral.C a => T a (a -> a -> a) getAdd = Cons Res.add getSub :: Integral.C a => T a (a -> a -> a) getSub = Cons Res.sub getNeg :: Integral.C a => T a (a -> a) getNeg = Cons Res.neg getAdditiveVars :: Integral.C a => T a (a, a -> a -> a, a -> a -> a, a -> a) getAdditiveVars = liftM4 (,,,) getZero getAdd getSub getNeg getMul :: Integral.C a => T a (a -> a -> a) getMul = Cons Res.mul getRingVars :: Integral.C a => T a (a, a -> a -> a) getRingVars = liftM2 (,) getOne getMul getDivide :: PID.C a => T a (a -> a -> a) getDivide = Cons Res.divide getRecip :: PID.C a => T a (a -> a) getRecip = Cons Res.recip getFieldVars :: PID.C a => T a (a -> a -> a, a -> a) getFieldVars = liftM2 (,) getDivide getRecip monadExample :: PID.C a => T a [a] monadExample = do (zero',(+~),(-~),negate') <- getAdditiveVars (one',(*~)) <- getRingVars ((/~),recip') <- getFieldVars let three = one'+one'+one' -- is easier if only NP.fromInteger is visible let seven = three+three+one' return [zero'*~three, one'/~three, recip' three, three *~ seven, one' +~ three +~ seven, zero' -~ three, negate' three +~ seven] runExample :: [Integer] runExample = let three = one+one+one eleven = three+three+three + one+one in concrete eleven monadExample