lude

Haskell prelude alternative
git clone git://git.rr3.xyz/lude | git clone gits://git.rr3.xyz/lude
Log | Files | Refs | README | LICENSE

commit 4442fcad3fba0446222e91d9d2052531f48d5f51
parent 166e07f464488e79fc091bd642aed744e39fe8b6
Author: Robert Russell <robert@rr3.xyz>
Date:   Wed, 14 Oct 2026 21:27:16 -0700

Algebra.Magma: init (WIP)

Diffstat:
Msrc/Lude/Algebra.hs | 1+
Asrc/Lude/Algebra/Magma.hs | 755+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 756 insertions(+), 0 deletions(-)

diff --git a/src/Lude/Algebra.hs b/src/Lude/Algebra.hs @@ -3,3 +3,4 @@ module Lude.Algebra ( ) where import Lude.Algebra.Category as X +import Lude.Algebra.Magma as X diff --git a/src/Lude/Algebra/Magma.hs b/src/Lude/Algebra/Magma.hs @@ -0,0 +1,755 @@ +{-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE UndecidableSuperClasses #-} + +module Lude.Algebra.Magma ( + -- * Magma tags + MagmaK, + Combinative, + Additive, + Multiplicative, + + -- * Semigroups + IsSemigroup_ (..), + IsSemigroup, + combine, + (<>), + (⋄), + IsAddSemigroup, + add, + (+), + IsMulSemigroup, + mul, + (*), + + -- * Partial cancellation + PartiallyLeftCancellable_ (..), + PartiallyRightCancellable_ (..), + PartiallyCancellable_, + PartiallyLeftCancellable, + cancelL', + (\\!), + PartiallyRightCancellable, + cancelR', + (//!), + PartiallyCancellable, + cancel', + PartiallyLeftSubtractable, + subtractL', + PartiallyRightSubtractable, + subtractR', + PartiallySubtractable, + subtract', + sub', + (-!), + PartiallyLeftDividable, + divideByL', + (\!), + PartiallyRightDividable, + divideByR', + (/!), + PartiallyDividable, + divideBy', + + -- * Decidable cancellation + DecidablyLeftCancellable_ (..), + DecidablyRightCancellable_ (..), + DecidablyCancellable_, + DecidablyLeftCancellable, + tryCancelL#, + (\\?#), + tryCancelL, + (\\?), + DecidablyRightCancellable, + tryCancelR#, + (//?#), + tryCancelR, + (//?), + DecidablyCancellable, + tryCancel#, + tryCancel, + DecidablyLeftSubtractable, + trySubtractL#, + trySubtractL, + DecidablyRightSubtractable, + trySubtractR#, + trySubtractR, + DecidablySubtractable, + trySubtract#, + trySubtract, + DecidablyLeftDividable, + tryDivideByL#, + (\?#), + tryDivideByL, + (\?), + DecidablyRightDividable, + tryDivideByR#, + (/?#), + tryDivideByR, + (/?), + DecidablyDividable, + tryDivideBy#, + tryDivideBy, + + -- * Monoids + IsMonoid_ (..), + IsMonoid, + neutral, + IsAddMonoid, + zero, + IsMulMonoid, + one, + + -- * Partial inverses + PartiallyHasInverses_ (..), + PartiallyHasInverses, + invert', + PartiallyHasNegations, + negate', + PartiallyHasReciprocals, + recip', + + -- * Decidable inverses + DecidablyHasInverses_ (..), + DecidablyHasInverses, + tryInvert#, + tryInvert, + DecidablyHasNegations, + tryNegate#, + tryNegate, + DecidablyHasReciprocals, + tryRecip#, + tryRecip, + + -- * Groups + IsGroup_, + IsGroup, + cancelL, + -- TODO: Rename the conflicting (\\) + -- (\\), + cancelR, + (//), + invert, + IsAddGroup, + subtractL, + subtractR, + subtract, + sub, + (-), + negate, + IsMulGroup, + divideByL, + divideByR, + (/), + divideBy, + recip, + + -- * Commutativity + Commutative_, + Commutative, + AddCommutative, + MulCommutative, + IsCommSemigroup, + IsCommAddSemigroup, + IsCommMulSemigroup, + IsCommMonoid, + IsCommAddMonoid, + IsCommMulMonoid, + IsCommGroup, + IsCommAddGroup, + IsCommMulGroup, + + -- * Rings + IsSemiring, + IsCommSemiring, + IsRing, + IsCommRing, + IsDivisionRing, + IsField, +) where + +import Data.Coerce +import Numeric.Natural (Natural) +import Numeric.Natural qualified as Base +import Prelude (Integer, Rational) +import Prelude qualified as Base + +import Lude.Algebra.Category.Core +import Lude.Function +import Lude.Haskell +import Lude.Maybe + +-- TODO: The "magma" terminology is a bit wrong/misleading for the ring-like +-- structures. + +-- TODO: Break this up. + +-- TODO: We should somehow connect these to the categorical abstractions, so +-- that we don't have two abstraction islands. E.g., maybe all these should be +-- required to form an Eilenberg-Moore algebra (except the truely +-- "non-algebraic" ones, like fields). + +-- TODO: Should the initial rig/ring maps (out of Natural/Integer) use +-- the categorical machinery for initial objects? + +-- TODO: newtype to view X as X-oid with one object, and vice versa. + +-- TODO: Should addition be commutative always? It conventionally is. + +-- TODO: Torsors + +-- TODO: Modular integers with arbitrary modulus (requires passing around +-- modulus; see Oleg paper) + +-- TODO: Invertible/Unit type (newtype wrapper or pair) for the group of units, +-- the non-oidified version of Iso + +-- TODO: Decidable sign for ordered ring-like things + +-- TODO: Left- and right- actions + +-- TODO: Localization / field of fractions / Ratio + +-- TODO: Euclidean div/mod + +-- TODO: +-- type Exp :: forall {r :: Repr}. Type# r -> Type# r +-- newtype Exp a = MkExp a +-- type Log :: forall {r :: Repr}. Type# r -> Type# r +-- newtype Log a = MkLog a + +-------------------------------------------------------------------------------- + +data MagmaB :: Brand +type MagmaK = OpenKind MagmaB + +-- The three standard magma tags. +data Combinative :: MagmaK +data Additive :: MagmaK +data Multiplicative :: MagmaK + +-------------------------------------------------------------------------------- +-- Private Util + +type MagmaClass_ :: Kind +type MagmaClass_ = MagmaK -> MagmaClass + +type MagmaClass :: Kind +type MagmaClass = forall {r :: Repr}. Type# r -> Constraint + +type UnaryOp :: MagmaClass -> Type +type UnaryOp c = forall {r :: Repr} (a :: Type# r). (c a) => Endo a + +type UnaryOpMaybe# :: MagmaClass -> Type +type UnaryOpMaybe# c = forall {r :: Repr} (a :: Type# r). (c a) => a -> Maybe# a + +type UnaryOpMaybe :: MagmaClass -> Type +type UnaryOpMaybe c = forall (a :: Type). (c a) => a -> Maybe a + +type BinaryOp :: MagmaClass -> Type +type BinaryOp c = forall {r :: Repr} (a :: Type# r). (c a) => Biendo a + +type BinaryOpMaybe# :: MagmaClass -> Type +type BinaryOpMaybe# c = forall {r :: Repr} (a :: Type# r). (c a) => a -> a -> Maybe# a + +type BinaryOpMaybe :: MagmaClass -> Type +type BinaryOpMaybe c = forall (a :: Type). (c a) => a -> a -> Maybe a + +type Comm :: Endo MagmaClass_ +class (c this a, Commutative_ this a) => Comm c this (a :: Type# r) +instance forall (c :: MagmaClass_) (this :: MagmaK) (r :: Repr) (a :: Type# r). (c this a, Commutative_ this a) => Comm c this a + +-------------------------------------------------------------------------------- + +-- TODO: Remove Functional# superclass? We currently require it for some +-- generic definitions, but we should probably allow any representation. + +-- | Semigroup +-- +-- __Laws:__ +-- - /@combine@ is associative:/ @(x ⋄ y) ⋄ z = x ⋄ (y ⋄ z)@ +type IsSemigroup_ :: MagmaClass_ +class (Functional# r) => IsSemigroup_ this (a :: Type# r) where + combine_ :: For this (Biendo a) + +type IsSemigroup = IsSemigroup_ Combinative :: MagmaClass +combine, (<>), (⋄) :: forall {r :: Repr} (a :: Type# r). (IsSemigroup a) => Biendo a +combine = combine_ Combinative +(<>) = combine +(⋄) = combine +infixl 5 <>, ⋄ + +type IsAddSemigroup = IsSemigroup_ Additive :: MagmaClass +add, (+) :: forall {r :: Repr} (a :: Type# r). (IsAddSemigroup a) => Biendo a +add = combine_ Additive +(+) = add +infixl 6 + + +type IsMulSemigroup = IsSemigroup_ Multiplicative :: MagmaClass +mul, (*) :: forall {r :: Repr} (a :: Type# r). (IsMulSemigroup a) => Biendo a +mul = combine_ Multiplicative +(*) = mul +infixl 7 * + +-------------------------------------------------------------------------------- + +-- TODO: Names suck here + +-- | Semigroup with computable left cancellation for left-cancellable elements +-- +-- __Laws:__ +-- - /Partial left cancellation:/ if @x@ is left-cancellative, then @(x \\!) ∘ (x ⋄)@ = @identity@ +-- +-- We don't specify @(x \\!)@ on elements outside the image of @(x ⋄)@. +-- +-- Typically, monoids should also implement `PartiallyHasInverses_` +type PartiallyLeftCancellable_ :: MagmaClass_ +class (IsSemigroup_ this a) => PartiallyLeftCancellable_ this (a :: Type# r) where + cancelL'_ :: For this (Biendo a) + +-- | Semigroup with computable right cancellation for right-cancellable elements +-- +-- __Laws:__ +-- - /Partial right cancellation:/ if @x@ is right-cancellative, then @(//! x) ∘ (⋄ x)@ = @identity@ +-- +-- We don't specify @(//! x)@ on elements outside the image of @(⋄ x)@. +-- +-- Typically, monoids should also implement `PartiallyHasInverses_` +type PartiallyRightCancellable_ :: MagmaClass_ +class (IsSemigroup_ this a) => PartiallyRightCancellable_ this (a :: Type# r) where + cancelR'_ :: For this (Biendo a) + +-- | Commutative semigroup with computable cancellation for cancellable elements +type PartiallyCancellable_ :: MagmaClass_ +class (Commutative_ this a, PartiallyLeftCancellable_ this a, PartiallyRightCancellable_ this a) => PartiallyCancellable_ this (a :: Type# r) + +instance (Commutative_ this a, PartiallyLeftCancellable_ this a, PartiallyRightCancellable_ this a) => PartiallyCancellable_ this (a :: Type# r) + +type PartiallyLeftCancellable = PartiallyLeftCancellable_ Combinative :: MagmaClass +cancelL', (\\!) :: BinaryOp PartiallyLeftCancellable +cancelL' = cancelL'_ Combinative +(\\!) = cancelL' +infixr 5 \\! + +type PartiallyRightCancellable = PartiallyRightCancellable_ Combinative :: MagmaClass +cancelR', (//!) :: BinaryOp PartiallyRightCancellable +cancelR' = cancelR'_ Combinative +(//!) = flip cancelR' +infixl 5 //! + +type PartiallyCancellable = PartiallyCancellable_ Combinative :: MagmaClass +cancel' :: BinaryOp PartiallyCancellable +cancel' = cancelR' + +type PartiallyLeftSubtractable = PartiallyLeftCancellable_ Additive :: MagmaClass +subtractL' :: BinaryOp PartiallyLeftSubtractable +subtractL' = cancelL'_ Additive + +type PartiallyRightSubtractable = PartiallyRightCancellable_ Additive :: MagmaClass +subtractR' :: BinaryOp PartiallyRightSubtractable +subtractR' = cancelR'_ Additive + +-- NOTE: There're no standard symbols for left/right-subtraction, because +-- usually one assumes additive operations are commutative. So we just +-- require commutativity for the subtraction symbols. + +type PartiallySubtractable = PartiallyCancellable_ Additive :: MagmaClass +subtract', sub', (-!) :: BinaryOp PartiallySubtractable +subtract' = subtractR' +sub' = flip subtract' +(-!) = sub' +infixl 6 -! + +type PartiallyLeftDividable = PartiallyLeftCancellable_ Multiplicative :: MagmaClass +divideByL', (\!) :: BinaryOp PartiallyLeftDividable +divideByL' = cancelL'_ Multiplicative +(\!) = divideByL' +infixr 7 \! + +type PartiallyRightDividable = PartiallyRightCancellable_ Multiplicative :: MagmaClass +divideByR', (/!) :: BinaryOp PartiallyRightDividable +divideByR' = cancelR'_ Multiplicative +(/!) = flip divideByR' +infixl 7 /! + +type PartiallyDividable = PartiallyCancellable_ Multiplicative :: MagmaClass +divideBy' :: BinaryOp PartiallyDividable +divideBy' = divideByR' + +-------------------------------------------------------------------------------- + +-- | Semigroup with "decidable left cancellation" (i.e., decidable +-- left-cancellability and decidable images of left-combination with +-- left-cancellable elements) +-- +-- __Laws:__ +-- - /Decidable left cancellation:/ if @x@ is left-cancellative and @y@ +-- factors (necessarily uniquely) as @y = x ⋄ z@, then @x \\? y@ = +-- @Just z@; otherwise, @x \\? y@ = @Nothing@ +-- +-- Typically, monoids should also implement `DecidablyHasInverses_` +type DecidablyLeftCancellable_ :: MagmaClass_ +class (PartiallyLeftCancellable_ this a) => DecidablyLeftCancellable_ this (a :: Type# r) where + tryCancelL_# :: For this (a -> a -> Maybe# a) + +-- | Semigroup with "decidable right cancellation" (i.e., decidable +-- right-cancellability and decidable images of right-combination with +-- right-cancellable elements) +-- +-- __Laws:__ +-- - /Decidable right cancellation:/ if @x@ is right-cancellative and @y@ +-- factors (necessarily uniquely) as @y = z ⋄ x@, then @y //? x@ = +-- @Just z@; otherwise, @y //? x@ = @Nothing@ +-- +-- Typically, monoids should also implement `DecidablyHasInverses_` +type DecidablyRightCancellable_ :: MagmaClass_ +class (PartiallyRightCancellable_ this a) => DecidablyRightCancellable_ this (a :: Type# r) where + tryCancelR_# :: For this (a -> a -> Maybe# a) + +-- | Commutative semigroup with "decidable cancellation" (i.e., decidable +-- cancellability and decidable images of combination with cancellable elements) +type DecidablyCancellable_ :: MagmaClass_ +class (Commutative_ this a, DecidablyLeftCancellable_ this a, DecidablyRightCancellable_ this a) => DecidablyCancellable_ this (a :: Type# r) + +instance (Commutative_ this a, DecidablyLeftCancellable_ this a, DecidablyRightCancellable_ this a) => DecidablyCancellable_ this (a :: Type# r) + +type DecidablyLeftCancellable = DecidablyLeftCancellable_ Combinative :: MagmaClass +tryCancelL#, (\\?#) :: BinaryOpMaybe# DecidablyLeftCancellable +tryCancelL, (\\?) :: BinaryOpMaybe DecidablyLeftCancellable +tryCancelL# = tryCancelL_# Combinative +(\\?#) = tryCancelL# +tryCancelL = coerce tryCancelL# +(\\?) = tryCancelL +infix 5 \\?#, \\? + +type DecidablyRightCancellable = DecidablyRightCancellable_ Combinative :: MagmaClass +tryCancelR#, (//?#) :: BinaryOpMaybe# DecidablyRightCancellable +tryCancelR, (//?) :: BinaryOpMaybe DecidablyRightCancellable +tryCancelR# = tryCancelR_# Combinative +(//?#) = flip tryCancelR# +tryCancelR = coerce tryCancelR# +(//?) = flip tryCancelR +infix 5 //?#, //? + +type DecidablyCancellable = DecidablyCancellable_ Combinative :: MagmaClass +tryCancel# :: BinaryOpMaybe# DecidablyCancellable +tryCancel :: BinaryOpMaybe DecidablyCancellable +tryCancel# = tryCancelR# +tryCancel = tryCancelR + +type DecidablyLeftSubtractable = DecidablyLeftCancellable_ Additive :: MagmaClass +trySubtractL# :: BinaryOpMaybe# DecidablyLeftSubtractable +trySubtractL :: BinaryOpMaybe DecidablyLeftSubtractable +trySubtractL# = tryCancelL_# Additive +trySubtractL = coerce trySubtractL# + +type DecidablyRightSubtractable = DecidablyRightCancellable_ Additive :: MagmaClass +trySubtractR# :: BinaryOpMaybe# DecidablyRightSubtractable +trySubtractR :: BinaryOpMaybe DecidablyRightSubtractable +trySubtractR# = tryCancelR_# Additive +trySubtractR = coerce trySubtractR# + +type DecidablySubtractable = DecidablyCancellable_ Additive :: MagmaClass +trySubtract# :: BinaryOpMaybe# DecidablySubtractable +trySubtract :: BinaryOpMaybe DecidablySubtractable +trySubtract# = trySubtractR# +trySubtract = trySubtractR + +type DecidablyLeftDividable = DecidablyLeftCancellable_ Multiplicative :: MagmaClass +tryDivideByL#, (\?#) :: BinaryOpMaybe# DecidablyLeftDividable +tryDivideByL, (\?) :: BinaryOpMaybe DecidablyLeftDividable +tryDivideByL# = tryCancelL_# Multiplicative +(\?#) = tryDivideByL# +tryDivideByL = coerce tryDivideByL# +(\?) = tryDivideByL +infix 7 \?#, \? + +type DecidablyRightDividable = DecidablyRightCancellable_ Multiplicative :: MagmaClass +tryDivideByR#, (/?#) :: BinaryOpMaybe# DecidablyRightDividable +tryDivideByR, (/?) :: BinaryOpMaybe DecidablyRightDividable +tryDivideByR# = tryCancelR_# Multiplicative +(/?#) = flip tryDivideByR# +tryDivideByR = coerce tryDivideByR# +(/?) = flip tryDivideByR +infix 7 /?#, /? + +type DecidablyDividable = DecidablyCancellable_ Multiplicative :: MagmaClass +tryDivideBy# :: BinaryOpMaybe# DecidablyDividable +tryDivideBy :: BinaryOpMaybe DecidablyDividable +tryDivideBy# = tryDivideByR# +tryDivideBy = tryDivideByR + +-------------------------------------------------------------------------------- + +-- | Monoid +-- +-- __Laws:__ +-- - /@neutral@ is a (left and right) identity element:/ @neutral ⋄ x = x = x ⋄ neutral@ +type IsMonoid_ :: MagmaClass_ +class (IsSemigroup_ this a) => IsMonoid_ this (a :: Type# r) where + neutral_ :: For this a + +type IsMonoid = IsMonoid_ Combinative :: MagmaClass +neutral :: forall {r :: Repr} (a :: Type# r). (IsMonoid a) => a +neutral = neutral_ Combinative + +type IsAddMonoid = IsMonoid_ Additive :: MagmaClass +zero :: forall {r :: Repr} (a :: Type# r). (IsAddMonoid a) => a +zero = neutral_ Additive + +type IsMulMonoid = IsMonoid_ Multiplicative :: MagmaClass +one :: forall {r :: Repr} (a :: Type# r). (IsMulMonoid a) => a +one = neutral_ Multiplicative + +-------------------------------------------------------------------------------- + +-- NOTE: One-sided (left/right) inverses are noncanonical (and apparently not +-- very useful, anyway), so we only model two-sided inverses. + +-- | Monoid with computable inverses for invertible elements +-- +-- __Laws:__ +-- - /Partial inversion:/ if @x@ has inverse @y@, then @invert' x = y@ +-- +-- We don't specify @invert'@ on non-invertible elements. +type PartiallyHasInverses_ :: MagmaClass_ +class (IsMonoid_ this a) => PartiallyHasInverses_ this (a :: Type# r) where + invert'_ :: For this (Endo a) + +type PartiallyHasInverses = PartiallyHasInverses_ Combinative :: MagmaClass +invert' :: UnaryOp PartiallyHasInverses +invert' = invert'_ Combinative + +type PartiallyHasNegations = PartiallyHasInverses_ Additive :: MagmaClass +negate' :: UnaryOp PartiallyHasNegations +negate' = invert'_ Additive + +type PartiallyHasReciprocals = PartiallyHasInverses_ Multiplicative :: MagmaClass +recip' :: UnaryOp PartiallyHasReciprocals +recip' = invert'_ Multiplicative + +-------------------------------------------------------------------------------- + +-- | Monoid with decidable invertibility and computable inverses for invertible +-- elements +-- +-- __Laws:__ +-- - /Decidable inversion:/ if @x@ has inverse @y@, then @tryInvert x@ = +-- @Just y@; otherwise, @tryInvert x = Nothing@ +type DecidablyHasInverses_ :: MagmaClass_ +class (PartiallyHasInverses_ this a) => DecidablyHasInverses_ this (a :: Type# r) where + tryInvert_# :: For this (a -> Maybe# a) + +type DecidablyHasInverses = DecidablyHasInverses_ Combinative :: MagmaClass +tryInvert# :: UnaryOpMaybe# DecidablyHasInverses +tryInvert :: UnaryOpMaybe DecidablyHasInverses +tryInvert# = tryInvert_# Combinative +tryInvert = coerce tryInvert# + +type DecidablyHasNegations = DecidablyHasInverses_ Additive :: MagmaClass +tryNegate# :: UnaryOpMaybe# DecidablyHasNegations +tryNegate :: UnaryOpMaybe DecidablyHasNegations +tryNegate# = tryInvert_# Additive +tryNegate = coerce tryNegate# + +type DecidablyHasReciprocals = DecidablyHasInverses_ Multiplicative :: MagmaClass +tryRecip# :: UnaryOpMaybe# DecidablyHasReciprocals +tryRecip :: UnaryOpMaybe DecidablyHasReciprocals +tryRecip# = tryInvert_# Multiplicative +tryRecip = coerce tryRecip# + +-------------------------------------------------------------------------------- + +-- | Group +-- +-- __Laws:__ +-- - /Every element is invertible:/ @isJust (tryInvert x)@ = @True@ +type IsGroup_ :: MagmaClass_ +class (DecidablyHasInverses_ this a, DecidablyLeftCancellable_ this a, DecidablyRightCancellable_ this a) => IsGroup_ this (a :: Type# r) + +type IsGroup = IsGroup_ Combinative :: MagmaClass +cancelL, (\\), cancelR, (//) :: BinaryOp IsGroup +invert :: UnaryOp IsGroup +cancelL = cancelL' +(\\) = (\\!) +cancelR = cancelR' +(//) = (//!) +invert = invert' +infixr 5 \\ +infixl 5 // + +type IsAddGroup = IsGroup_ Additive :: MagmaClass +subtractL, subtractR :: BinaryOp IsAddGroup +subtract, sub, (-) :: BinaryOp IsCommAddGroup +negate :: UnaryOp IsAddGroup +subtractL = subtractL' +subtractR = subtractR' +subtract = subtract' +sub = sub' +(-) = (-!) +negate = negate' +infixl 6 - + +type IsMulGroup = IsGroup_ Multiplicative :: MagmaClass +divideByL, divideByR, (/) :: BinaryOp IsMulGroup -- NOTE: (\) is reserved in Haskell :( +divideBy :: BinaryOp IsCommMulGroup +recip :: UnaryOp IsMulGroup +divideByL = divideByL' +divideByR = divideByR' +(/) = (/!) +divideBy = divideBy' +recip = recip' +infixl 7 / + +-------------------------------------------------------------------------------- + +-- | Commutative semigroup +-- +-- __Laws:__ +-- - /@combine@ is commutative:/ @x ⋄ y = y ⋄ x@ +type Commutative_ :: MagmaClass_ +class (IsSemigroup_ this a) => Commutative_ this (a :: Type# r) + +type Commutative = Commutative_ Combinative :: MagmaClass +type AddCommutative = Commutative_ Additive :: MagmaClass +type MulCommutative = Commutative_ Multiplicative :: MagmaClass + +type IsCommSemigroup = Comm IsSemigroup_ Combinative :: MagmaClass +type IsCommAddSemigroup = Comm IsSemigroup_ Additive :: MagmaClass +type IsCommMulSemigroup = Comm IsSemigroup_ Multiplicative :: MagmaClass + +type IsCommMonoid = Comm IsMonoid_ Combinative :: MagmaClass +type IsCommAddMonoid = Comm IsMonoid_ Additive :: MagmaClass +type IsCommMulMonoid = Comm IsMonoid_ Multiplicative :: MagmaClass + +type IsCommGroup = Comm IsGroup_ Combinative :: MagmaClass +type IsCommAddGroup = Comm IsGroup_ Additive :: MagmaClass +type IsCommMulGroup = Comm IsGroup_ Multiplicative :: MagmaClass + +-------------------------------------------------------------------------------- + +-- TODO: Generalize to take two MagmaK's + +-- TODO: Laws + +-- TODO: DecidableZero for decidable division rings (and fields)? + +type IsSemiring :: MagmaClass +class (IsCommAddMonoid a, IsMulMonoid a) => IsSemiring (a :: Type# r) + +type IsCommSemiring :: MagmaClass +class (IsSemiring a, MulCommutative a) => IsCommSemiring (a :: Type# r) +instance (IsSemiring a, MulCommutative a) => IsCommSemiring (a :: Type# r) + +type IsRing :: MagmaClass +class (IsSemiring a, IsAddGroup a) => IsRing (a :: Type# r) + +type IsCommRing :: MagmaClass +class (IsRing a, MulCommutative a) => IsCommRing (a :: Type# r) +instance (IsRing a, MulCommutative a) => IsCommRing (a :: Type# r) + +type IsDivisionRing :: MagmaClass +class (IsRing a, PartiallyLeftDividable a, PartiallyRightDividable a, PartiallyHasReciprocals a) => IsDivisionRing a + +type IsField :: MagmaClass +class (IsDivisionRing a, MulCommutative a) => IsField a +instance (IsDivisionRing a, MulCommutative a) => IsField a + +-------------------------------------------------------------------------------- + +baseZero :: (Base.Num a) => a +baseZero = 0 where fromInteger = Base.fromInteger + +baseOne :: (Base.Num a) => a +baseOne = 1 where fromInteger = Base.fromInteger + +instance (Base.Num a) => IsSemigroup_ Additive (BaseInterop a) where combine_ _ = coerce (Base.+) +instance (Base.Num a) => PartiallyLeftCancellable_ Additive (BaseInterop a) where cancelL'_ _ = coerce Base.subtract +instance (Base.Num a) => DecidablyLeftCancellable_ Additive (BaseInterop a) where tryCancelL_# _ = coerce $ Just .* Base.subtract +instance (Base.Num a) => PartiallyRightCancellable_ Additive (BaseInterop a) where cancelR'_ _ = coerce Base.subtract +instance (Base.Num a) => DecidablyRightCancellable_ Additive (BaseInterop a) where tryCancelR_# _ = coerce $ Just .* Base.subtract +instance (Base.Num a) => PartiallyHasInverses_ Additive (BaseInterop a) where invert'_ _ = coerce Base.negate +instance (Base.Num a) => DecidablyHasInverses_ Additive (BaseInterop a) where tryInvert_# _ = coerce $ Just . Base.negate +instance (Base.Num a) => IsMonoid_ Additive (BaseInterop a) where neutral_ _ = coerce baseZero +instance (Base.Num a) => IsGroup_ Additive (BaseInterop a) +instance (Base.Num a) => Commutative_ Additive (BaseInterop a) +instance (Base.Num a) => IsSemigroup_ Multiplicative (BaseInterop a) where combine_ _ = coerce (Base.*) +instance (Base.Num a) => IsMonoid_ Multiplicative (BaseInterop a) where neutral_ _ = coerce baseOne +instance (Base.Num a) => IsSemiring (BaseInterop a) +instance (Base.Num a) => IsRing (BaseInterop a) +instance (Base.Fractional a) => PartiallyLeftCancellable_ Multiplicative (BaseInterop a) where cancelL'_ _ = coerce \x y -> Base.recip x Base.* y +instance (Base.Fractional a) => PartiallyRightCancellable_ Multiplicative (BaseInterop a) where cancelR'_ _ = coerce $ flip (Base./) +instance (Base.Fractional a) => PartiallyHasInverses_ Multiplicative (BaseInterop a) where invert'_ _ = coerce Base.recip +instance (Base.Fractional a) => IsDivisionRing (BaseInterop a) + +-------------------------------------------------------------------------------- + +baseDivNonZero :: forall (a :: Type). (Base.Eq a, Base.Fractional a) => a -> a -> Maybe a +baseDivNonZero x y = if y Base.== baseZero then Nothing else Just (x Base./ y) + +baseRecipNonZero :: forall (a :: Type). (Base.Eq a, Base.Fractional a) => a -> Maybe a +baseRecipNonZero x = if x Base.== baseZero then Nothing else Just (Base.recip x) + +deriving via BaseInterop Natural instance IsSemigroup_ Additive Natural +deriving via BaseInterop Natural instance PartiallyLeftCancellable_ Additive Natural +instance DecidablyLeftCancellable_ Additive Natural where tryCancelL_# _ = coerce $ flip Base.minusNaturalMaybe +deriving via BaseInterop Natural instance PartiallyRightCancellable_ Additive Natural +instance DecidablyRightCancellable_ Additive Natural where tryCancelR_# _ = coerce $ flip Base.minusNaturalMaybe +deriving via BaseInterop Natural instance IsMonoid_ Additive Natural +deriving via BaseInterop Natural instance Commutative_ Additive Natural +deriving via BaseInterop Natural instance IsSemigroup_ Multiplicative Natural +deriving via BaseInterop Natural instance IsMonoid_ Multiplicative Natural +instance Commutative_ Multiplicative Natural +deriving via BaseInterop Natural instance IsSemiring Natural + +deriving via BaseInterop Integer instance IsSemigroup_ Additive Integer +deriving via BaseInterop Integer instance PartiallyLeftCancellable_ Additive Integer +deriving via BaseInterop Integer instance DecidablyLeftCancellable_ Additive Integer +deriving via BaseInterop Integer instance PartiallyRightCancellable_ Additive Integer +deriving via BaseInterop Integer instance DecidablyRightCancellable_ Additive Integer +deriving via BaseInterop Integer instance IsMonoid_ Additive Integer +deriving via BaseInterop Integer instance PartiallyHasInverses_ Additive Integer +deriving via BaseInterop Integer instance DecidablyHasInverses_ Additive Integer +deriving via BaseInterop Integer instance IsGroup_ Additive Integer +deriving via BaseInterop Integer instance Commutative_ Additive Integer +deriving via BaseInterop Integer instance IsSemigroup_ Multiplicative Integer +deriving via BaseInterop Integer instance IsMonoid_ Multiplicative Integer +instance Commutative_ Multiplicative Integer +deriving via BaseInterop Integer instance IsSemiring Integer +deriving via BaseInterop Integer instance IsRing Integer + +deriving via BaseInterop Rational instance IsSemigroup_ Additive Rational +deriving via BaseInterop Rational instance PartiallyLeftCancellable_ Additive Rational +deriving via BaseInterop Rational instance DecidablyLeftCancellable_ Additive Rational +deriving via BaseInterop Rational instance PartiallyRightCancellable_ Additive Rational +deriving via BaseInterop Rational instance DecidablyRightCancellable_ Additive Rational +deriving via BaseInterop Rational instance IsMonoid_ Additive Rational +deriving via BaseInterop Rational instance PartiallyHasInverses_ Additive Rational +deriving via BaseInterop Rational instance DecidablyHasInverses_ Additive Rational +deriving via BaseInterop Rational instance IsGroup_ Additive Rational +deriving via BaseInterop Rational instance Commutative_ Additive Rational +deriving via BaseInterop Rational instance IsSemigroup_ Multiplicative Rational +deriving via BaseInterop Rational instance IsMonoid_ Multiplicative Rational +instance Commutative_ Multiplicative Rational +deriving via BaseInterop Rational instance IsSemiring Rational +deriving via BaseInterop Rational instance IsRing Rational +deriving via BaseInterop Rational instance PartiallyLeftCancellable_ Multiplicative Rational +instance DecidablyLeftCancellable_ Multiplicative Rational where tryCancelL_# _ = coerce $ flip baseDivNonZero +deriving via BaseInterop Rational instance PartiallyRightCancellable_ Multiplicative Rational +instance DecidablyRightCancellable_ Multiplicative Rational where tryCancelR_# _ = coerce $ flip baseDivNonZero +deriving via BaseInterop Rational instance PartiallyHasInverses_ Multiplicative Rational +instance DecidablyHasInverses_ Multiplicative Rational where tryInvert_# _ = coerce baseRecipNonZero +deriving via BaseInterop Rational instance IsDivisionRing Rational + +-- TODO: Switch-out base combinators for Lude's +instance (IsSemigroup_ this a) => IsSemigroup_ this (r -> a) where combine_ _ = Base.liftA2 (combine_ this) +instance (PartiallyLeftCancellable_ this a) => PartiallyLeftCancellable_ this (r -> a) where cancelL'_ _ = Base.liftA2 (cancelL'_ this) +instance (PartiallyRightCancellable_ this a) => PartiallyRightCancellable_ this (r -> a) where cancelR'_ _ = Base.liftA2 (cancelR'_ this) +instance (IsMonoid_ this a) => IsMonoid_ this (r -> a) where neutral_ _ = Base.const (neutral_ this) +instance (PartiallyHasInverses_ this a) => PartiallyHasInverses_ this (r -> a) where invert'_ _ = Base.fmap (invert'_ this) +instance (IsGroup_ this a) => DecidablyLeftCancellable_ this (r -> a) where tryCancelL_# _ = just# .* cancelL'_ this +instance (IsGroup_ this a) => DecidablyRightCancellable_ this (r -> a) where tryCancelR_# _ = just# .* cancelR'_ this +instance (IsGroup_ this a) => DecidablyHasInverses_ this (r -> a) where tryInvert_# _ = just# . invert'_ this +instance (IsGroup_ this a) => IsGroup_ this (r -> a) +instance (Commutative_ this a) => Commutative_ this (r -> a) +instance (IsSemiring a) => IsSemiring (r -> a) +instance (IsRing a) => IsRing (r -> a)