content: {-# language FlexibleInstances #-}
  {-# language Safe #-}
  -- |
  -- Module       : Data.Group.Multiplicative
  -- Copyright    : (c) 2020-2021 Emily Pillmore
  -- License      : BSD-style
  --
  -- Maintainer   : Emily Pillmore <emilypi@cohomolo.gy>,
  --                Reed Mullanix <reedmullanix@gmail.com>
  -- Stability    : stable
  -- Portability  : non-portable
  --
  -- This module contains definitions for 'MultiplicativeGroup' and
  -- 'MultiplicativeAbelianGroup', along with the relevant combinators.
  --
  module Data.Group.Multiplicative
  ( -- * Multiplicative Groups
    MultiplicativeGroup
    -- ** combinators
  , (/)
  , (*)
  , (^)
  , power
    -- * Multiplicative abelian groups
  , MultiplicativeAbelianGroup
  ) where
  
  
  import Data.Functor.Const
  import Data.Functor.Identity
  import Data.Group
  import Data.Proxy
  import Data.Semigroup
  
  import Prelude hiding ((^), (/), (*))
  
  infixl 7 /, *
  infixr 8 ^
  
  -- $setup
  --
  -- >>> :set -XPackageImports
  -- >>> import Prelude (Int, Rational)
  -- >>> import qualified Prelude as P
  -- >>> import "group-theory" Data.Group
  -- >>> import Data.Monoid
  -- >>> import Data.Semigroup
  -- >>> :set -XTypeApplications
  
  -- -------------------------------------------------------------------- --
  -- Multiplicative groups
  
  -- | An multiplicative group is a 'Group' whose operation can be thought of
  -- as multiplication in some sense.
  --
  -- For example, the multiplicative group of rationals \( (ℚ, 1, *) \).
  --
  class Group g => MultiplicativeGroup g
  
  instance MultiplicativeGroup ()
  instance MultiplicativeGroup b => MultiplicativeGroup (a -> b)
  instance MultiplicativeGroup a => MultiplicativeGroup (Dual a)
  instance Fractional a => MultiplicativeGroup (Product a)
  instance (MultiplicativeGroup a, MultiplicativeGroup b) => MultiplicativeGroup (a,b)
  instance (MultiplicativeGroup a, MultiplicativeGroup b, MultiplicativeGroup c) => MultiplicativeGroup (a,b,c)
  instance (MultiplicativeGroup a, MultiplicativeGroup b, MultiplicativeGroup c, MultiplicativeGroup d) => MultiplicativeGroup (a,b,c,d)
  instance (MultiplicativeGroup a, MultiplicativeGroup b, MultiplicativeGroup c, MultiplicativeGroup d, MultiplicativeGroup e) => MultiplicativeGroup (a,b,c,d,e)
  instance MultiplicativeGroup a => MultiplicativeGroup (Const a b)
  instance MultiplicativeGroup a => MultiplicativeGroup (Identity a)
  instance MultiplicativeGroup a => MultiplicativeGroup (Proxy a)
  
  -- | Infix alias for multiplicative inverse.
  --
  -- === __Examples__:
  --
  -- >>> let x = Product (4 :: Rational)
  -- >>> x / 2
  -- Product {getProduct = 2 % 1}
  --
  (/) :: MultiplicativeGroup a => a -> a -> a
  (/) = minus
  {-# inline (/) #-}
  
  -- | Infix alias for multiplicative @('<>')@.
  --
  -- === __Examples__:
  --
  -- >>> Product (2 :: Rational) * Product (3 :: Rational)
  -- Product {getProduct = 6 % 1}
  --
  (*) :: MultiplicativeGroup g => g -> g -> g
  (*) = (<>)
  {-# inline (*) #-}
  
  -- | Infix alias for 'power'.
  --
  -- === __Examples__:
  --
  -- >>> let x = Product (3 :: Rational)
  -- >>> x ^ 3
  -- Product {getProduct = 27 % 1}
  --
  (^) :: (Integral n, MultiplicativeGroup a) => a -> n -> a
  (^) = power
  {-# inline (^) #-}
  
  -- | Multiply an element of a multiplicative group by itself @n@-many times.
  --
  -- This represents @ℕ@-indexed powers of an element @g@ of
  -- a multiplicative group, i.e. iterated products of group elements.
  -- This is representable by the universal property
  -- \( C(x, ∏_n g) ≅ C(x, g)^n \).
  --
  -- === __Examples__:
  --
  -- >>> power (Product (3 :: Rational)) 3
  -- Product {getProduct = 27 % 1}
  --
  power :: (Integral n, MultiplicativeGroup g) => g -> n -> g
  power a n = gtimes n a
  {-# inline power #-}
  
  -- -------------------------------------------------------------------- --
  -- Multiplicative abelian groups
  
  -- | A multiplicative abelian group is a 'Group' whose operation can be thought of
  -- as commutative multiplication in some sense. Almost all multiplicative groups
  -- are abelian.
  --
  class (MultiplicativeGroup g, Abelian g) => MultiplicativeAbelianGroup g
  instance MultiplicativeAbelianGroup ()
  instance MultiplicativeAbelianGroup b => MultiplicativeAbelianGroup (a -> b)
  instance MultiplicativeAbelianGroup a => MultiplicativeAbelianGroup (Dual a)
  instance Fractional a => MultiplicativeAbelianGroup (Product a)
  instance (MultiplicativeAbelianGroup a, MultiplicativeAbelianGroup b) => MultiplicativeAbelianGroup (a,b)
  instance (MultiplicativeAbelianGroup a, MultiplicativeAbelianGroup b, MultiplicativeAbelianGroup c) => MultiplicativeAbelianGroup (a,b,c)
  instance (MultiplicativeAbelianGroup a, MultiplicativeAbelianGroup b, MultiplicativeAbelianGroup c, MultiplicativeAbelianGroup d) => MultiplicativeAbelianGroup (a,b,c,d)
  instance (MultiplicativeAbelianGroup a, MultiplicativeAbelianGroup b, MultiplicativeAbelianGroup c, MultiplicativeAbelianGroup d, MultiplicativeAbelianGroup e) => MultiplicativeAbelianGroup (a,b,c,d,e)
  instance MultiplicativeAbelianGroup a => MultiplicativeAbelianGroup (Const a b)
  instance MultiplicativeAbelianGroup a => MultiplicativeAbelianGroup (Identity a)
  instance MultiplicativeAbelianGroup a => MultiplicativeAbelianGroup (Proxy a)
  