{-# OPTIONS_GHC -Wno-missing-import-lists #-}

-- | This module reexports algebraic typeclasses.
--
-- @since 0.1
module Numeric.Algebra
  ( -- * Motivation
    -- $motivation

    -- * Solution
    -- $solution

    -- ** Algebraic Typeclasses
    module Numeric.Algebra.Additive,
    module Numeric.Algebra.Multiplicative,
    module Numeric.Algebra.MetricSpace,
    module Numeric.Algebra.Normed,
    module Numeric.Algebra.Rings,
    module Numeric.Algebra.Space,
  )
where

import Numeric.Algebra.Additive
import Numeric.Algebra.MetricSpace
import Numeric.Algebra.Multiplicative
import Numeric.Algebra.Normed
import Numeric.Algebra.Rings
import Numeric.Algebra.Space

-- $motivation
-- The primary interface to numerical operations in Haskell is 'Num'.
-- Unfortunately, 'Num' has a key limitation: it is "too large". For example,
-- if we want to opt-in to addition, we must also opt-in to subtraction,
-- multiplication, and integer literal conversions. These may not make sense
-- for the type at hand (e.g. naturals), so we are stuck either providing an
-- invariant-breaking dangerous implementation (e.g. defining subtraction for
-- arbitrary naturals) or throwing runtime errors.

-- $solution
-- @algebra-simple@'s approach is to split this functionality into multiple
-- typeclasses, so types can opt-in to exactly as much functionality as they
-- want. The typeclasses are inspired by abstract algebra. The algebraic
-- hierarchy can be found in the following diagram. An arrow @A -> B@ should
-- be read as "@B@ is an @A@". For example, a 'Module' is both a 'Semimodule'
-- and an 'AGroup'.
--
-- ![Algebraic hierarchy](./diagrams/hierarchy.png)
--
-- A longer description can be found in the table below, along with the 'Num'
-- functionality they are intended to replace:
--
-- __Scalar classes__
--
-- +------------------------+-------------------------+-----------+----------+
-- | Typeclass              | Description             | New       | 'Num'    |
-- +========================+=========================+===========+==========+
-- | 'ASemigroup'           | Addition.               | '(.+.)'   | '(+)'    |
-- |                        |                         |           |          |
-- +------------------------+-------------------------+-----------+----------+
-- | 'AMonoid'              | 'ASemigroup' with       | 'zero'    |          |
-- |                        | identity.               |           |          |
-- +------------------------+-------------------------+-----------+----------+
-- | 'AGroup'               | Subtraction.            | '(.-.)'   | '(-)'    |
-- |                        |                         |           |          |
-- |                        |                         |           |          |
-- +------------------------+-------------------------+-----------+----------+
-- | 'MSemigroup'           | Multiplication.         | '(.*.)'   | '(*)'    |
-- |                        |                         |           |          |
-- +------------------------+-------------------------+-----------+----------+
-- | 'MMonoid'              | 'MSemigroup' with       | 'one'     |          |
-- |                        | identity.               |           |          |
-- +------------------------+-------------------------+-----------+----------+
-- | 'MGroup'               | Division.               | '(.%.)'   | 'div',   |
-- |                        |                         |           | '(/)'    |
-- +------------------------+-------------------------+-----------+----------+
-- | 'MEuclidean'           | Euclidean division.     | 'mdivMod' | 'divMod' |
-- |                        |                         |           |          |
-- +------------------------+-------------------------+-----------+----------+
-- | 'Normed'               | Types that support a    | 'norm',   | 'abs',   |
-- |                        | "norm".                 | 'sgn'     | 'signum' |
-- +------------------------+-------------------------+-----------+----------+
-- | 'Quartaring'           | 'ASemigroup' and        |           |          |
-- |                        | 'MSemigroup'.           |           |          |
-- +------------------------+-------------------------+-----------+----------+
-- | 'Hemiring'             | 'AMonoid' and           |           |          |
-- |                        | 'Quartaring'.           |           |          |
-- +------------------------+-------------------------+-----------+----------+
-- | 'Demiring'             | 'MMonoid' and           |           |          |
-- |                        | 'Quartaring'.           |           |          |
-- +------------------------+-------------------------+-----------+----------+
-- | 'Semiring'             | 'Hemiring' and          |           |          |
-- |                        | 'Demiring'.             |           |          |
-- +------------------------+-------------------------+-----------+----------+
-- | 'PseudoRing'           | 'AGroup' and            |           |          |
-- |                        | 'Hemiring'.             |           |          |
-- +------------------------+-------------------------+-----------+----------+
-- | 'Ring'                 | 'Semiring' and          |           |          |
-- |                        | 'PseudoRing'.           |           |          |
-- +------------------------+-------------------------+-----------+----------+
-- | 'PseudoSemifield'      | 'MGroup' and            |           |          |
-- |                        | 'Demiring'.             |           |          |
-- +------------------------+-------------------------+-----------+----------+
-- | 'Semifield'            | 'Semiring' and          |           |          |
-- |                        | 'PseudoSemifield'.      |           |          |
-- +------------------------+-------------------------+-----------+----------+
-- | 'Field'                | 'Ring' and              |           |          |
-- |                        | 'Semifield'.            |           |          |
-- +------------------------+-------------------------+-----------+----------+
--
-- __Space-like classes__
--
-- +-------------------------+-------------------------+----------+
-- | Typeclass               | Description             | New      |
-- +=========================+=========================+==========+
-- | 'MSemiSpace'            | Scalar multiplication.  | '(.*)',  |
-- |                         |                         | '(*.)'   |
-- |                         |                         |          |
-- +-------------------------+-------------------------+----------+
-- | 'MSpace'                | Scalar division.        | '(.%)',  |
-- |                         |                         | '(%.)'   |
-- |                         |                         |          |
-- +-------------------------+-------------------------+----------+
-- | 'Quartamodule'          | 'ASemigroup' and        |          |
-- |                         | 'MSemiSpace'.           |          |
-- +-------------------------+-------------------------+----------+
-- | 'Hemimodule'            | 'AMonoid' and           |          |
-- |                         | 'Quartamodule'.         |          |
-- +-------------------------+-------------------------+----------+
-- | 'Demimodule'            | 'Quartamodule'.         |          |
-- |                         |                         |          |
-- +-------------------------+-------------------------+----------+
-- | 'Semimodule'            | 'Hemimodule' and        |          |
-- |                         | 'Demimodule'.           |          |
-- +-------------------------+-------------------------+----------+
-- | 'PseudoModule'          | 'AGroup' and            |          |
-- |                         | 'Hemimodule' .          |          |
-- +-------------------------+-------------------------+----------+
-- | 'Module'                | 'Semimodule' and        |          |
-- |                         | 'PseudoModule' .        |          |
-- +-------------------------+-------------------------+----------+
-- | 'PseudoSemivectorSpace' | 'MSpace' and            |          |
-- |                         | 'Demimodule'.           |          |
-- +-------------------------+-------------------------+----------+
-- | 'SemivectorSpace'       | 'Semimodule' and        |          |
-- |                         | 'Demimodule'.           |          |
-- +-------------------------+-------------------------+----------+
-- | 'VectorSpace'           | 'Module' and            |          |
-- |                         | 'SemivectorSpace'.      |          |
-- +-------------------------+-------------------------+----------+
--
-- We have the following guiding principles:
--
-- 1. Simplicity
--
--     This is not a comprehensive implementation of abstract algebra, merely
--     the classes needed to replace the usual 'Num'-like functionality. For
--     the former, see [algebra](https://hackage.haskell.org/package/algebra).
--
-- 2. Practicality
--
--     When there is tension between practicality and theoretical "purity", we
--     favor the former. To wit:
--
--     * We provide two semigroup\/monoid\/group hierarchies:
--        'ASemigroup'\/'AMonoid'\/'AGroup' and
--        'MSemigroup'\/'MMonoid'\/'MGroup'. Formally this is clunky,
--        but it allows us to:
--
--         * Reuse the same operator for ring multiplication and types that
--           have sensible multiplication but cannot be rings (e.g. naturals).
--
--         * Provide both addition and multiplication without an explosion of
--           newtype wrappers.
--
--     * Leniency vis-à-vis algebraic laws
--
--         For instance, integers cannot satisfy the field laws, and floats do
--         not satisfy anything, as their equality is nonsense. Nevertheless,
--         we provide instances for them. Working with technically unlawful
--         numerical instances is extremely common, so we take the stance that
--         it is better to provide such instances (albeit with known
--         limitations) than to forgo them completely (read: integer division
--         is useful). The only instances we disallow are those likely to
--         cause runtime errors (e.g. natural subtraction) or break expected
--         invariants.
--
--     * Division classes (i.e. 'MGroup', 'VectorSpace') have their own division
--       function that must be implemented. Theoretically this is unnecessary,
--       as we need only a function @inv :: a -> a@ and we
--       can then define division as @x .%. d = d .*. inv d@. But this will
--       not work for many types (e.g. integers), so we force users to define a
--       (presumably sensible) '(.%.)', so there is no chance of accidentally
--       using a nonsensical @inv@.
--
-- 3. Safety
--
--     Instances that break the type's invariants
--     (@instance 'Ring' 'GHC.Natural'@), are banned. Furthermore, instances
--     that are /highly/ likely to go wrong
--     (e.g. 'Rational' with bounded integral types) are also forbidden.
--
-- 4. Ergonomics
--
--      We choose new operators that do not clash with prelude.
--
-- We provide instances for built-in numeric types where it makes sense.