content: module Numeric.Partial.Group
    ( PartialGroup(..)
    ) where
  
  import Control.Applicative
  import Data.Int
  import Data.Word
  import Numeric.Partial.Semigroup
  import Numeric.Partial.Monoid
  import Numeric.Natural
  
  class PartialMonoid a => PartialGroup a where
    pnegate :: a -> Maybe a
    pnegate = pminus pzero
  
    pminus :: a -> a -> Maybe a
    pminus a b = padd a =<< pnegate b 
  
    psubtract :: a -> a -> Maybe a
    psubtract a b = pnegate a >>= (`padd` b)
  
  instance PartialGroup Int where
    pnegate = Just . negate
  
  instance PartialGroup Integer where
    pnegate = Just . negate
  
  instance PartialGroup Int8 where
    pnegate = Just . negate
  
  instance PartialGroup Int16 where
    pnegate = Just . negate
  
  instance PartialGroup Int32 where
    pnegate = Just . negate
  
  instance PartialGroup Int64 where
    pnegate = Just . negate
  
  instance PartialGroup Word where
    pnegate = Just . negate
  
  instance PartialGroup Word8 where
    pnegate = Just . negate
  
  instance PartialGroup Word16 where
    pnegate = Just . negate
  
  instance PartialGroup Word32 where
    pnegate = Just . negate
  
  instance PartialGroup Word64 where
    pnegate = Just . negate
  
  instance PartialGroup Natural where
    pnegate 0 = Just 0
    pnegate _ = Nothing
    pminus a b 
      | a < b = Nothing
      | otherwise = Just (a - b)
    psubtract a b 
      | a > b = Nothing
      | otherwise = Just (b - a)
  
  instance PartialGroup () where
    pnegate _ = Just () 
    pminus _ _ = Just ()
    psubtract _ _ = Just ()
  
  instance (PartialGroup a, PartialGroup b) => PartialGroup (a, b) where
    pnegate (a, b) = (,) <$> pnegate a <*> pnegate b
    pminus (a, b) (i, j) = (,) <$> pminus a i <*> pminus b j
    psubtract (a, b) (i, j) = (,) <$> psubtract a i <*> psubtract b j
  
  instance (PartialGroup a, PartialGroup b, PartialGroup c) => PartialGroup (a, b, c) where
    pnegate (a, b, c) = (,,) <$> pnegate a <*> pnegate b <*> pnegate c
    pminus (a, b, c) (i, j, k) = (,,) <$> pminus a i <*> pminus b j <*> pminus c k
    psubtract (a, b, c) (i, j, k) = (,,) <$> psubtract a i <*> psubtract b j <*> psubtract c k
  
  instance (PartialGroup a, PartialGroup b, PartialGroup c, PartialGroup d) => PartialGroup (a, b, c, d) where
    pnegate (a, b, c, d) = (,,,) <$> pnegate a <*> pnegate b <*> pnegate c <*> pnegate d
    pminus (a, b, c, d) (i, j, k, l) = (,,,) <$> pminus a i <*> pminus b j <*> pminus c k <*> pminus d l
    psubtract (a, b, c, d) (i, j, k, l) = (,,,) <$> psubtract a i <*> psubtract b j <*> psubtract c k <*> psubtract d l
  
  instance (PartialGroup a, PartialGroup b, PartialGroup c, PartialGroup d, PartialGroup e) => PartialGroup (a, b, c, d, e) where
    pnegate (a, b, c, d, e) = (,,,,) <$> pnegate a <*> pnegate b <*> pnegate c <*> pnegate d <*> pnegate e
    pminus (a, b, c, d, e) (i, j, k, l, m) = (,,,,) <$> pminus a i <*> pminus b j <*> pminus c k <*> pminus d l <*> pminus e m
    psubtract (a, b, c, d, e) (i, j, k, l, m) = (,,,,) <$> psubtract a i <*> psubtract b j <*> psubtract c k <*> psubtract d l <*> psubtract e m
  