-- | Additive classes
module NumHask.Algebra.Additive
  ( Additive (..),
    Sum (..),
    sum,
    accsum,
    Subtractive (..),
  )
where

import Data.Int (Int16, Int32, Int64, Int8)
import Data.Semigroup (Semigroup (..))
import Data.Traversable (mapAccumL)
import Data.Word (Word, Word16, Word32, Word64, Word8)
import GHC.Natural (Natural (..))
import Prelude (Bool, Double, Eq, Float, Int, Integer, Ord, Show, fromInteger)
import qualified Prelude as P

-- $setup
--
-- >>> :set -XRebindableSyntax
-- >>> import NumHask.Prelude

-- | or [Addition](https://en.wikipedia.org/wiki/Addition)
--
-- For practical reasons, we begin the class tree with 'NumHask.Algebra.Additive.Additive'.  Starting with  'NumHask.Algebra.Group.Associative' and 'NumHask.Algebra.Group.Unital', or using 'Data.Semigroup.Semigroup' and 'Data.Monoid.Monoid' from base tends to confuse the interface once you start having to disinguish between (say) monoidal addition and monoidal multiplication.
--
-- prop> \a -> zero + a == a
-- prop> \a -> a + zero == a
-- prop> \a b c -> (a + b) + c == a + (b + c)
-- prop> \a b -> a + b == b + a
--
-- By convention, (+) is regarded as commutative, but this is not universal, and the introduction of another symbol which means non-commutative addition seems a bit dogmatic.
--
-- >>> zero + 1
-- 1
--
-- >>> 1 + 1
-- 2
class Additive a where
  infixl 6 +
  (+) :: a -> a -> a

  zero :: a

-- | A wrapper for an Additive which distinguishes the additive structure
newtype Sum a = Sum
  { forall a. Sum a -> a
getSum :: a
  }
  deriving (Sum a -> Sum a -> Bool
forall a. Eq a => Sum a -> Sum a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Sum a -> Sum a -> Bool
$c/= :: forall a. Eq a => Sum a -> Sum a -> Bool
== :: Sum a -> Sum a -> Bool
$c== :: forall a. Eq a => Sum a -> Sum a -> Bool
Eq, Sum a -> Sum a -> Bool
Sum a -> Sum a -> Ordering
Sum a -> Sum a -> Sum a
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall {a}. Ord a => Eq (Sum a)
forall a. Ord a => Sum a -> Sum a -> Bool
forall a. Ord a => Sum a -> Sum a -> Ordering
forall a. Ord a => Sum a -> Sum a -> Sum a
min :: Sum a -> Sum a -> Sum a
$cmin :: forall a. Ord a => Sum a -> Sum a -> Sum a
max :: Sum a -> Sum a -> Sum a
$cmax :: forall a. Ord a => Sum a -> Sum a -> Sum a
>= :: Sum a -> Sum a -> Bool
$c>= :: forall a. Ord a => Sum a -> Sum a -> Bool
> :: Sum a -> Sum a -> Bool
$c> :: forall a. Ord a => Sum a -> Sum a -> Bool
<= :: Sum a -> Sum a -> Bool
$c<= :: forall a. Ord a => Sum a -> Sum a -> Bool
< :: Sum a -> Sum a -> Bool
$c< :: forall a. Ord a => Sum a -> Sum a -> Bool
compare :: Sum a -> Sum a -> Ordering
$ccompare :: forall a. Ord a => Sum a -> Sum a -> Ordering
Ord, Int -> Sum a -> ShowS
forall a. Show a => Int -> Sum a -> ShowS
forall a. Show a => [Sum a] -> ShowS
forall a. Show a => Sum a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Sum a] -> ShowS
$cshowList :: forall a. Show a => [Sum a] -> ShowS
show :: Sum a -> String
$cshow :: forall a. Show a => Sum a -> String
showsPrec :: Int -> Sum a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Sum a -> ShowS
Show)

instance (Additive a) => P.Semigroup (Sum a) where
  Sum a
a <> :: Sum a -> Sum a -> Sum a
<> Sum a
b = forall a. a -> Sum a
Sum (a
a forall a. Additive a => a -> a -> a
+ a
b)

instance (Additive a) => P.Monoid (Sum a) where
  mempty :: Sum a
mempty = forall a. a -> Sum a
Sum forall a. Additive a => a
zero

deriving instance (Additive a) => Additive (Sum a)

-- | Compute the sum of a 'Data.Foldable.Foldable'.
--
-- >>> sum [0..10]
-- 55
sum :: (Additive a, P.Foldable f) => f a -> a
sum :: forall a (f :: * -> *). (Additive a, Foldable f) => f a -> a
sum = forall a. Sum a -> a
getSum forall b c a. (b -> c) -> (a -> b) -> a -> c
P.. forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
P.foldMap forall a. a -> Sum a
Sum

-- | Compute the accumulating sum of a 'Data.Traversable.Traversable'.
--
-- >>> accsum [0..10]
-- [0,1,3,6,10,15,21,28,36,45,55]
accsum :: (Additive a, P.Traversable f) => f a -> f a
accsum :: forall a (f :: * -> *). (Additive a, Traversable f) => f a -> f a
accsum = forall a b. (a, b) -> b
P.snd forall b c a. (b -> c) -> (a -> b) -> a -> c
P.. forall (t :: * -> *) s a b.
Traversable t =>
(s -> a -> (s, b)) -> s -> t a -> (s, t b)
mapAccumL (\a
a a
b -> (a
a forall a. Additive a => a -> a -> a
+ a
b, a
a forall a. Additive a => a -> a -> a
+ a
b)) forall a. Additive a => a
zero

-- | or [Subtraction](https://en.wikipedia.org/wiki/Subtraction)
--
-- prop> \a -> a - a == zero
-- prop> \a -> negate a == zero - a
-- prop> \a -> negate a + a == zero
-- prop> \a -> a + negate a == zero
--
--
-- >>> negate 1
-- -1
--
-- >>> 1 - 2
-- -1
class (Additive a) => Subtractive a where
  {-# MINIMAL (-) | negate #-}

  negate :: a -> a
  negate a
a = forall a. Additive a => a
zero forall a. Subtractive a => a -> a -> a
- a
a

  infixl 6 -
  (-) :: a -> a -> a
  a
a - a
b = a
a forall a. Additive a => a -> a -> a
+ forall a. Subtractive a => a -> a
negate a
b

instance Additive Double where
  + :: Double -> Double -> Double
(+) = forall a. Num a => a -> a -> a
(P.+)
  zero :: Double
zero = Double
0

instance Subtractive Double where
  negate :: Double -> Double
negate = forall a. Num a => a -> a
P.negate

instance Additive Float where
  + :: Float -> Float -> Float
(+) = forall a. Num a => a -> a -> a
(P.+)
  zero :: Float
zero = Float
0

instance Subtractive Float where
  negate :: Float -> Float
negate = forall a. Num a => a -> a
P.negate

instance Additive Int where
  + :: Int -> Int -> Int
(+) = forall a. Num a => a -> a -> a
(P.+)
  zero :: Int
zero = Int
0

instance Subtractive Int where
  negate :: Int -> Int
negate = forall a. Num a => a -> a
P.negate

instance Additive Integer where
  + :: Integer -> Integer -> Integer
(+) = forall a. Num a => a -> a -> a
(P.+)
  zero :: Integer
zero = Integer
0

instance Subtractive Integer where
  negate :: Integer -> Integer
negate = forall a. Num a => a -> a
P.negate

instance Additive Bool where
  + :: Bool -> Bool -> Bool
(+) = Bool -> Bool -> Bool
(P.||)
  zero :: Bool
zero = Bool
P.False

instance Additive Natural where
  + :: Natural -> Natural -> Natural
(+) = forall a. Num a => a -> a -> a
(P.+)
  zero :: Natural
zero = Natural
0

instance Subtractive Natural where
  negate :: Natural -> Natural
negate = forall a. Num a => a -> a
P.negate

instance Additive Int8 where
  + :: Int8 -> Int8 -> Int8
(+) = forall a. Num a => a -> a -> a
(P.+)
  zero :: Int8
zero = Int8
0

instance Subtractive Int8 where
  negate :: Int8 -> Int8
negate = forall a. Num a => a -> a
P.negate

instance Additive Int16 where
  + :: Int16 -> Int16 -> Int16
(+) = forall a. Num a => a -> a -> a
(P.+)
  zero :: Int16
zero = Int16
0

instance Subtractive Int16 where
  negate :: Int16 -> Int16
negate = forall a. Num a => a -> a
P.negate

instance Additive Int32 where
  + :: Int32 -> Int32 -> Int32
(+) = forall a. Num a => a -> a -> a
(P.+)
  zero :: Int32
zero = Int32
0

instance Subtractive Int32 where
  negate :: Int32 -> Int32
negate = forall a. Num a => a -> a
P.negate

instance Additive Int64 where
  + :: Int64 -> Int64 -> Int64
(+) = forall a. Num a => a -> a -> a
(P.+)
  zero :: Int64
zero = Int64
0

instance Subtractive Int64 where
  negate :: Int64 -> Int64
negate = forall a. Num a => a -> a
P.negate

instance Additive Word where
  + :: Word -> Word -> Word
(+) = forall a. Num a => a -> a -> a
(P.+)
  zero :: Word
zero = Word
0

instance Subtractive Word where
  negate :: Word -> Word
negate = forall a. Num a => a -> a
P.negate

instance Additive Word8 where
  + :: Word8 -> Word8 -> Word8
(+) = forall a. Num a => a -> a -> a
(P.+)
  zero :: Word8
zero = Word8
0

instance Subtractive Word8 where
  negate :: Word8 -> Word8
negate = forall a. Num a => a -> a
P.negate

instance Additive Word16 where
  + :: Word16 -> Word16 -> Word16
(+) = forall a. Num a => a -> a -> a
(P.+)
  zero :: Word16
zero = Word16
0

instance Subtractive Word16 where
  negate :: Word16 -> Word16
negate = forall a. Num a => a -> a
P.negate

instance Additive Word32 where
  + :: Word32 -> Word32 -> Word32
(+) = forall a. Num a => a -> a -> a
(P.+)
  zero :: Word32
zero = Word32
0

instance Subtractive Word32 where
  negate :: Word32 -> Word32
negate = forall a. Num a => a -> a
P.negate

instance Additive Word64 where
  + :: Word64 -> Word64 -> Word64
(+) = forall a. Num a => a -> a -> a
(P.+)
  zero :: Word64
zero = Word64
0

instance Subtractive Word64 where
  negate :: Word64 -> Word64
negate = forall a. Num a => a -> a
P.negate

instance (Additive b) => Additive (a -> b) where
  a -> b
f + :: (a -> b) -> (a -> b) -> a -> b
+ a -> b
f' = \a
a -> a -> b
f a
a forall a. Additive a => a -> a -> a
+ a -> b
f' a
a
  zero :: a -> b
zero a
_ = forall a. Additive a => a
zero

instance (Subtractive b) => Subtractive (a -> b) where
  negate :: (a -> b) -> a -> b
negate a -> b
f = forall a. Subtractive a => a -> a
negate forall b c a. (b -> c) -> (a -> b) -> a -> c
P.. a -> b
f