packages feed

moonlight-algebra-0.1.0.0: src-abstract/Moonlight/Algebra/Pure/Group.hs

{-# LANGUAGE GHC2024 #-}

-- | Lawful group refinements over the standard 'Semigroup' and 'Monoid'
-- classes, plus operation-selecting wrappers for carriers with more than one
-- legitimate monoidal structure.
--
-- A raw carrier such as 'Integer' admits both additive and multiplicative
-- monoids. Haskell instances are global, so 'Additive' and 'Multiplicative'
-- make the selected operation explicit instead of pretending the carrier has
-- one canonical monoid.
module Moonlight.Algebra.Pure.Group
  ( Additive (..),
    Multiplicative (..),
    Semigroup (..),
    Monoid (..),
    Group (..),
    AbelianGroup,
  )
where

import Data.Kind (Constraint, Type)
import Moonlight.Core
  ( AdditiveGroup (..),
    AdditiveMonoid (..),
    MultiplicativeMonoid (..),
  )
import Prelude
  ( Eq,
    Monoid (..),
    Num,
    Ord,
    Semigroup (..),
    Show,
  )

type Additive :: Type -> Type
newtype Additive a = Additive {getAdditive :: a}
  deriving stock (Eq, Ord, Show)
  deriving newtype (Num)

type Multiplicative :: Type -> Type
newtype Multiplicative a = Multiplicative {getMultiplicative :: a}
  deriving stock (Eq, Ord, Show)
  deriving newtype (Num)

type Group :: Type -> Constraint
class Monoid group => Group group where
  groupInverse :: group -> group

  groupDifference :: group -> group -> group
  groupDifference left right =
    left <> groupInverse right

type AbelianGroup :: Type -> Constraint
class Group group => AbelianGroup group

instance AdditiveMonoid a => Semigroup (Additive a) where
  Additive left <> Additive right =
    Additive (add left right)

instance AdditiveMonoid a => Monoid (Additive a) where
  mempty =
    Additive zero

instance AdditiveGroup a => Group (Additive a) where
  groupInverse (Additive value) =
    Additive (neg value)

instance AdditiveGroup a => AbelianGroup (Additive a)

instance MultiplicativeMonoid a => Semigroup (Multiplicative a) where
  Multiplicative left <> Multiplicative right =
    Multiplicative (mul left right)

instance MultiplicativeMonoid a => Monoid (Multiplicative a) where
  mempty =
    Multiplicative one