    {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
    module Numeric.Ring.Rng
      ( RngRing(..)
      , rngRingHom
      , liftRngHom
      ) where

    import Numeric.Algebra
    import Prelude hiding ((+),(-),(*),(/),replicate,negate,subtract,fromIntegral)

    -- | The free Ring given a Rng obtained by adjoining Z, such that
    --
    -- > RngRing r = n*1 + r
    --
    -- This ring is commonly denoted r^.
    data RngRing r = RngRing !Integer r deriving (Show,Read)

    instance Abelian r => Additive (RngRing r) where
      RngRing n a + RngRing m b = RngRing (n + m) (a + b)
      sinnum1p n (RngRing m a) = RngRing ((1 + toInteger n) * m) (sinnum1p n a)

    instance Abelian r => Abelian (RngRing r)

    instance (Abelian r, Monoidal r) => LeftModule Natural (RngRing r) where
      n .* RngRing m a = RngRing (toInteger n * m) (sinnum n a)

    instance (Abelian r, Monoidal r) => RightModule Natural (RngRing r) where
      RngRing m a *. n = RngRing (toInteger n * m) (sinnum n a)

    instance (Abelian r, Monoidal r) => Monoidal (RngRing r) where
      zero = RngRing 0 zero
      sinnum n (RngRing m a) = RngRing (toInteger n * m) (sinnum n a)

    instance (Abelian r, Group r) => LeftModule Integer (RngRing r) where
      n .* RngRing m a = RngRing (toInteger n * m) (times n a)

    instance (Abelian r, Group r) => RightModule Integer (RngRing r) where
      RngRing m a *. n = RngRing (toInteger n * m) (times n a)

    instance (Abelian r, Group r) => Group (RngRing r) where
      RngRing n a - RngRing m b = RngRing (n - m) (a - b)
      negate (RngRing n a) = RngRing (negate n) (negate a)
      subtract (RngRing n a) (RngRing m b) = RngRing (subtract n m) (subtract a b)
      times n (RngRing m a) = RngRing (toInteger n * m) (times n a)

    instance Rng r => Multiplicative (RngRing r) where
      RngRing n a * RngRing m b = RngRing (n*m) (times n b + times m a + a * b)

    instance (Commutative r, Rng r) => Commutative (RngRing r)

    instance Rng s => LeftModule (RngRing s) (RngRing s) where
      (.*) = (*)

    instance Rng s => RightModule (RngRing s) (RngRing s) where
      (*.) = (*)

    instance Rng r => Unital (RngRing r) where
      one = RngRing 1 zero

    instance (Rng r, Division r) => Division (RngRing r) where
      RngRing n a / RngRing m b = RngRing 0 $ (times n one + a) / (times m one + b)

    instance Rng r => Semiring (RngRing r)

    instance Rng r => Rig (RngRing r)

    instance Rng r => Ring (RngRing r)

    -- | The rng homomorphism from r to RngRing r
    rngRingHom :: r -> RngRing r
    rngRingHom = RngRing 0

    -- | given a rng homomorphism from a rng r into a ring s, liftRngHom yields a ring homomorphism from the ring `r^` into `s`.
    liftRngHom :: Ring s => (r -> s) -> RngRing r -> s
    liftRngHom g (RngRing n a) = times n one + g a