    {-# 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