{-# OPTIONS -fno-implicit-prelude #-}
module Number.ResidueClass.Func where

import qualified Number.ResidueClass as Res

import qualified Algebra.PrincipalIdealDomain as PID
import qualified Algebra.IntegralDomain as Integral
import qualified Algebra.Field          as Field
import qualified Algebra.Ring           as Ring

import PreludeBase
import NumericPrelude hiding (zero, one, )

import qualified Prelude        as P
import qualified NumericPrelude as NP

{- |
Here a residue class is a representative
and the modulus is an argument.
You cannot show a value of type 'T',
you can only show it with respect to a concrete modulus.
Values cannot be compared,
because the comparison result depends on the modulus.
-}
newtype T a = Cons (a -> a)

concrete :: a -> T a -> a
concrete m (Cons r) = r m

fromRepresentative :: (Integral.C a) => a -> T a
fromRepresentative = Cons . mod

lift0 :: (a -> a) -> T a
lift0 = Cons

lift1 :: (a -> a -> a) -> T a -> T a
lift1 f (Cons x) = Cons \$ \m -> f m (x m)

lift2 :: (a -> a -> a -> a) -> T a -> T a -> T a
lift2 f (Cons x) (Cons y) = Cons \$ \m -> f m (x m) (y m)

zero :: (Additive.C a) => T a
zero = Cons \$ const Additive.zero

one :: (Ring.C a) => T a
one  = Cons \$ const NP.one

fromInteger :: (Integral.C a) => Integer -> T a
fromInteger = fromRepresentative . NP.fromInteger

equal :: Eq a => a -> T a -> T a -> Bool
equal m (Cons x) (Cons y)  =  x m == y m

instance  (Integral.C a) => Additive.C (T a)  where
zero		=  zero
(-)			=  lift2 Res.sub
negate		=  lift1 Res.neg

instance  (Integral.C a) => Ring.C (T a)  where
one			=  one
(*)			=  lift2 Res.mul
fromInteger		=  Number.ResidueClass.Func.fromInteger

instance  (PID.C a) => Field.C (T a)  where
(/)			=  lift2 Res.divide
recip               =  (NP.one /)
fromRational'	=  error "no conversion from rational to residue class"

{-
NumericPrelude.fromInteger seems to be not available at GHCi's prompt sometimes.
But Prelude.fromInteger requires Prelude.Num instance.
-}

-- legacy instances for work with GHCi
legacyInstance :: a
legacyInstance =
error "legacy Ring.C instance for simple input of numeric literals"

instance (P.Num a, Integral.C a) => P.Num (T a) where
fromInteger = Number.ResidueClass.Func.fromInteger
negate = negate --for unary minus
(+)    = legacyInstance
(*)    = legacyInstance
abs    = legacyInstance
signum = legacyInstance

instance Eq (T a) where
(==) = error "ResidueClass.Func: (==) not implemented"

instance Show (T a) where
show = error "ResidueClass.Func: 'show' not implemented"