{-
Copyright (C) 2011 Dr. Alistair Ward
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
-}
{- |
[@AUTHOR@] Dr. Alistair Ward
[@DESCRIPTION@]
* Describes a /ring/ and operations on its members.
* .
* .
-}
module Factory.Data.Ring(
-- * Type-classes
Ring(..),
-- * Types
-- ** Data.types
-- Product,
-- Sum,
-- * Functions
product',
sum',
-- ** Operators
(=^)
) where
import qualified Data.Monoid
import qualified Factory.Math.DivideAndConquer as Math.DivideAndConquer
infixl 6 =+= --Same as (+).
infixl 6 =-= --Same as (-).
infixl 7 =*= --Same as (*).
infixr 8 =^ --Same as (^).
{- |
* Define both the operations applicable to all members of the /ring/, and its mandatory members.
* Minimal definition; '=+=', '=*=', 'additiveInverse', 'multiplicativeIdentity', 'additiveIdentity'.
-}
class Ring r where
(=+=) :: r -> r -> r -- ^ Addition of two members; required to be /commutative/; .
(=*=) :: r -> r -> r -- ^ Multiplication of two members.
additiveInverse :: r -> r -- ^ The operand required to yield /zero/ under addition; .
multiplicativeIdentity :: r -- ^ The /identity/-member under multiplication; .
additiveIdentity :: r -- ^ The /identity/-member under addition (AKA /zero/); .
(=-=) :: r -> r -> r -- ^ Subtract the two specified /ring/-members.
l =-= r = l =+= additiveInverse r --Default implementation.
square :: r -> r -- ^ Square the ring.
square r = r =*= r --Default implementation; there may be a more efficient one.
{- |
* Raise a /ring/-member to the specified positive integral power.
* Exponentiation is implemented as a sequence of either squares of, or multiplications by, the /ring/-member;
.
-}
(=^) :: (Ring r, Eq r, Integral power) => r -> power -> r
_ =^ 0 = multiplicativeIdentity
ring =^ power
| power < 0 = error $ "Factory.Data.Ring.(=^):\tthe result isn't guaranteed to be a ring-member, for power=" ++ show power
| ring `elem` [additiveIdentity, multiplicativeIdentity] = ring
| otherwise = slave power
where
slave 1 = ring
slave n = (if r == 0 {-even-} then id else (=*= ring)) . square $ slave q where
(q, r) = n `quotRem` 2
-- | Does for 'Ring', what 'Data.Monoid.Product' does for type 'Num', in that it makes it an instance of 'Data.Monoid.Monoid' under multiplication.
newtype Product p = MkProduct {
getProduct :: p -- ^ Access the polymorphic payload.
} deriving (Read, Show)
instance Ring r => Data.Monoid.Monoid (Product r) where
mempty = MkProduct multiplicativeIdentity
MkProduct x `mappend` MkProduct y = MkProduct $ x =*= y
-- | Returns the /product/ of the list of /ring/-members.
product' :: Ring r => Math.DivideAndConquer.BisectionRatio -> Math.DivideAndConquer.MinLength -> [r] -> r
--product' _ _ = getProduct . Data.Monoid.mconcat . map MkProduct
product' ratio minLength = getProduct . Math.DivideAndConquer.divideAndConquer ratio minLength . map MkProduct
-- | Does for 'Ring', what 'Data.Monoid.Sum' does for type 'Num', in that it makes it an instance of 'Data.Monoid.Monoid' under addition.
newtype Sum s = MkSum {
getSum :: s -- ^ Access the polymorphic payload.
} deriving (Read, Show)
instance Ring r => Data.Monoid.Monoid (Sum r) where
mempty = MkSum additiveIdentity
MkSum x `mappend` MkSum y = MkSum $ x =+= y
-- | Returns the /sum/ of the list of /ring/-members.
sum' :: Ring r => Math.DivideAndConquer.BisectionRatio -> Math.DivideAndConquer.MinLength -> [r] -> r
--sum' _ _ = getSum . Data.Monoid.mconcat . map MkSum
sum' ratio minLength = getSum . Math.DivideAndConquer.divideAndConquer ratio minLength . map MkSum