ideas-1.0: src/Common/Algebra/CoField.hs
{-# LANGUAGE GeneralizedNewtypeDeriving, PatternGuards #-}
-----------------------------------------------------------------------------
-- Copyright 2011, Open Universiteit Nederland. This file is distributed
-- under the terms of the GNU General Public License. For more information,
-- see the file "LICENSE.txt", which is included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer : bastiaan.heeren@ou.nl
-- Stability : provisional
-- Portability : portable (depends on ghc)
--
-----------------------------------------------------------------------------
module Common.Algebra.CoField
( CoSemiRing(..), CoRing(..), CoField(..)
, SmartField(..)
, (.+.), (.-.), neg, (.*.), (./.)
) where
import Common.Algebra.CoGroup
import Common.Algebra.Field
import Common.Algebra.Group
import Common.Algebra.SmartGroup
import Control.Arrow ((***))
import Control.Monad
import qualified Control.Applicative as A
class CoSemiRing a where
-- additive
isPlus :: a -> Maybe (a, a)
isZero :: a -> Bool
-- multiplicative
isTimes :: a -> Maybe (a, a)
isOne :: a -> Bool
-- Minimal complete definition: plusInverse or <->
class CoSemiRing a => CoRing a where
isNegate :: a -> Maybe a
isMinus :: a -> Maybe (a, a)
-- default definition
isMinus _ = Nothing
class CoRing a => CoField a where
isRecip :: a -> Maybe a
isDivision :: a -> Maybe (a, a)
-- default definition
isDivision _ = Nothing
instance CoSemiRing a => CoMonoid (Additive a) where
isEmpty = isZero . fromAdditive
isAppend = fmap (Additive *** Additive) . isPlus . fromAdditive
instance CoRing a => CoGroup (Additive a) where
isInverse = fmap Additive . isNegate . fromAdditive
isAppendInv = fmap (Additive *** Additive) . isMinus . fromAdditive
instance CoSemiRing a => CoMonoid (Multiplicative a) where
isEmpty = isOne . fromMultiplicative
isAppend = fmap (Multiplicative *** Multiplicative) . isTimes . fromMultiplicative
instance CoField a => CoGroup (Multiplicative a) where
isInverse = fmap Multiplicative . isRecip . fromMultiplicative
isAppendInv = fmap (Multiplicative *** Multiplicative) . isDivision . fromMultiplicative
instance CoSemiRing a => CoMonoidZero (Multiplicative a) where
isMonoidZero = isZero . fromMultiplicative
------------------------------------------------------------------
newtype SmartField a = SmartField {fromSmartField :: a}
deriving (CoSemiRing, CoRing, CoField)
instance Functor SmartField where -- could be derived
fmap f = SmartField . f . fromSmartField
instance A.Applicative SmartField where
pure = SmartField
SmartField f <*> SmartField a = SmartField (f a)
instance (CoField a, Field a) => SemiRing (SmartField a) where
zero = SmartField zero
one = SmartField one
SmartField a <+> SmartField b = SmartField $ fromAdditive $ fromSmartGroup $
SmartGroup (Additive a) <> SmartGroup (Additive b)
a <*> b
| Just x <- isNegate a = plusInverse (x <*> b)
| Just x <- isNegate b = plusInverse (a <*> x)
| isZero a || isZero b = zero
| isOne a = b
| isOne b = a
| Just (x, y) <- isTimes b = (a <*> x) <*> y
| Just (x, y) <- isDivision b = (a <*> x) </> y
| otherwise = A.liftA2 (<*>) a b
instance (CoField a, Field a) => Ring (SmartField a) where
plusInverse = SmartField . fromAdditive . fromSmartGroup . inverse
. SmartGroup . Additive . fromSmartField
SmartField a <-> SmartField b = SmartField $ fromAdditive $ fromSmartGroup $
SmartGroup (Additive a) <>- SmartGroup (Additive b)
instance (CoField a, Field a) => Field (SmartField a) where
timesInverse a
| Just x <- isNegate a = plusInverse (timesInverse x)
| Just (x, y) <- isDivision a, isOne y = x
| otherwise = A.liftA timesInverse a
a </> b
| Just x <- isNegate a = plusInverse (x </> b)
| Just x <- isNegate b = plusInverse (a </> x)
| isOne b = a
| Just (x, y) <- isDivision a = x </> (y <*> b)
| otherwise = A.liftA2 (</>) a b
------------------------------------------------------------------
infixl 7 .*., ./.
infixl 6 .-., .+.
(.+.) :: (CoField a, Field a) => a -> a -> a
a .+. b = fromSmartField $ SmartField a <+> SmartField b
(.-.) :: (CoField a, Field a) => a -> a -> a
a .-. b = fromSmartField $ SmartField a <-> SmartField b
neg :: (CoField a, Field a) => a -> a
neg = fromSmartField . plusInverse . SmartField
(.*.) :: (CoField a, Field a) => a -> a -> a
a .*. b = fromSmartField $ SmartField a <*> SmartField b
(./.) :: (CoField a, Field a) => a -> a -> a
a ./. b = fromSmartField $ SmartField a </> SmartField b
-- myrecip :: (CoField a, Field a) => a -> a
-- myrecip = fromSmartField . timesInverse . SmartField