content: {-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
  module Numeric.Rng.Zero
    ( ZeroRng(..)
    ) where
  
  import Numeric.Algebra
  import Data.Foldable (toList)
  import Prelude hiding ((+),(-),negate,subtract,replicate)
  
  -- *** The Zero Rng for an Abelian Group, adding the trivial product
  --
  -- > _ * _ = zero 
  --
  -- which distributes over (+)
  
  -- ZeroRng/runZeroRng witness an additive Abelian group isomorphism to the zero rng.
  newtype ZeroRng r = ZeroRng { runZeroRng :: r } deriving (Eq,Ord,Show,Read)
  
  instance Additive r => Additive (ZeroRng r) where
    ZeroRng a + ZeroRng b = ZeroRng (a + b)
    sumWith1 f = ZeroRng . sumWith1 (runZeroRng . f)
  
  instance Idempotent r => Idempotent (ZeroRng r)
  
  instance Abelian r => Abelian (ZeroRng r)
  
  instance Monoidal r => Monoidal (ZeroRng r) where
    zero = ZeroRng zero
    sumWith f = ZeroRng . sumWith (runZeroRng . f)
    sinnum n (ZeroRng a) = ZeroRng (sinnum n a)
    
  instance Group r => Group (ZeroRng r) where
    ZeroRng a - ZeroRng b = ZeroRng (a - b)
    negate (ZeroRng a) = ZeroRng (negate a)
    subtract (ZeroRng a) (ZeroRng b) = ZeroRng (subtract a b)
    times n (ZeroRng a) = ZeroRng (times n a)
  
  instance Monoidal r => Multiplicative (ZeroRng r) where
    _ * _ = zero
    productWith1 f as = case toList as of
      [] -> error "productWith1: empty Foldable1"
      [a] -> f a
      _   -> zero
  
  instance (Monoidal r, Abelian r) => Semiring (ZeroRng r)
  instance Monoidal r => Commutative (ZeroRng r)
  instance (Group r, Abelian r) => Rng (ZeroRng r)
  instance Monoidal r => LeftModule Natural (ZeroRng r) where
    (.*) = sinnum
  instance Monoidal r => RightModule Natural (ZeroRng r) where
    m *. n = sinnum n m
  instance Group r => LeftModule Integer (ZeroRng r) where
    (.*) = times
  instance Group r => RightModule Integer (ZeroRng r) where
    m *. n = times n m
  