{-# LANGUAGE RebindableSyntax #-}
{-# OPTIONS_HADDOCK prune #-}

-- | Numeric classes.
module NumHask
  ( -- * Usage
    -- $setup

    -- * Overview
    -- $overview
    -- $pictures

    -- * Prelude Mappings
    -- $mapping

    -- * Extensions
    -- $extensions

    -- * Additive
    Additive (..),
    sum,
    accsum,
    Subtractive (..),

    -- * Multiplicative
    Multiplicative (..),
    product,
    accproduct,
    Divisive (..),

    -- * Ring
    Distributive,
    Ring,
    StarSemiring (..),
    KleeneAlgebra,
    InvolutiveRing (..),
    two,

    -- * Field
    Field,
    ExpField (..),
    QuotientField (..),
    TrigField (..),
    infinity,
    negInfinity,
    nan,
    half,

    -- * Lattice
    JoinSemiLattice (..),
    joinLeq,
    (<\),
    MeetSemiLattice (..),
    meetLeq,
    (</),
    BoundedJoinSemiLattice (..),
    BoundedMeetSemiLattice (..),

    -- * Action
    AdditiveAction (..),
    (+|),
    SubtractiveAction (..),
    (-|),
    MultiplicativeAction (..),
    (*|),
    DivisiveAction (..),
    (/|),
    Module,

    -- * Metric
    Basis (..),
    Absolute,
    Sign,
    EndoBased,
    abs,
    signum,
    distance,
    Direction (..),
    Polar (..),
    polar,
    coord,
    Epsilon (..),
    aboutEqual,
    nearZero,
    (~=),

    -- * Complex
    Complex (..),
    (+:),
    realPart,
    imagPart,

    -- * Integral
    Integral (..),
    ToIntegral (..),
    ToInt,
    FromIntegral (..),
    FromInteger (..),
    FromInt,
    even,
    odd,
    (^^),
    (^),

    -- * Rational
    Ratio (..),
    Rational,
    ToRatio (..),
    FromRatio (..),
    FromRational (..),
    reduce,
    gcd,

    -- * Exceptions
    NumHaskException (..),
    throw,
  )
where

import NumHask.Algebra.Action
  ( AdditiveAction (..),
    DivisiveAction (..),
    Module,
    MultiplicativeAction (..),
    SubtractiveAction (..),
    (*|),
    (+|),
    (-|),
    (/|),
  )
import NumHask.Algebra.Additive
  ( Additive (..),
    Subtractive (..),
    accsum,
    sum,
  )
import NumHask.Algebra.Field
  ( ExpField (..),
    Field,
    QuotientField (..),
    TrigField (..),
    half,
    infinity,
    nan,
    negInfinity,
  )
import NumHask.Algebra.Lattice
  ( BoundedJoinSemiLattice (..),
    BoundedMeetSemiLattice (..),
    JoinSemiLattice (..),
    MeetSemiLattice (..),
    joinLeq,
    meetLeq,
    (</),
    (<\),
  )
import NumHask.Algebra.Metric
  ( Absolute,
    Basis (..),
    Direction (..),
    EndoBased,
    Epsilon (..),
    Polar (..),
    Sign,
    aboutEqual,
    abs,
    coord,
    distance,
    nearZero,
    polar,
    signum,
    (~=),
  )
import NumHask.Algebra.Multiplicative
  ( Divisive (..),
    Multiplicative (..),
    accproduct,
    product,
  )
import NumHask.Algebra.Ring
  ( Distributive,
    InvolutiveRing (..),
    KleeneAlgebra,
    Ring,
    StarSemiring (..),
    two,
  )
import NumHask.Data.Complex (Complex (..), imagPart, realPart, (+:))
import NumHask.Data.Integral
  ( FromInt,
    FromInteger (..),
    FromIntegral (..),
    Integral (..),
    ToInt,
    ToIntegral (..),
    even,
    odd,
    (^),
    (^^),
  )
import NumHask.Data.Rational
  ( FromRatio (..),
    FromRational (..),
    Ratio (..),
    Rational,
    ToRatio (..),
    gcd,
    reduce,
  )
import NumHask.Exception (NumHaskException (..), throw)

-- $setup
--
-- >>> :set -XRebindableSyntax
-- >>> import NumHask.Prelude
-- >>> 1+1
-- 2

-- $extensions
--
-- [RebindableSyntax](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/rebindable_syntax.html)
-- is recommended for use with numhask.
--
-- As a replacement for the numerical classes, numhask clashes significantly with an
-- unqualified import of the @Prelude@. Either numhask modules should be qualified,
-- or prelude turned off with the NoImplicitPrelude extension, or with RebindableSyntax,
-- which implies NoImplicitPrelude.
--
-- == defaulting
--
-- Without RebindableSyntax, numeric literals default as follows:
--
-- >>> :set -XNoRebindableSyntax
-- >>> :t 1
-- 1 :: Num a => a
--
-- >>> :t 1.0
-- 1.0 :: Fractional a => a
--
-- With RebindableSyntax (which also switches NoImplicitPrelude on) literal numbers change to the numhask types, 'FromInteger' and 'FromRational':
--
-- >>> :set -XRebindableSyntax
-- >>> :t 1
-- 1 :: FromInteger a => a
--
-- >>> :t 1.0
-- 1.0 :: FromRational a => a
--
-- >>> 1
-- 1
--
-- >>> 1.0
-- 1.0
--
-- RebindableSyntax is a tradeoff, however, and usage comes attached with other non-numeric changes
-- that "NumHask.Prelude" attempts to counteract.
--
-- See [haskell2010 Section 4.3.4](https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-750004.3) for the nuts and bolts to defaulting.
--
-- The effect of [ExtendedDefaultRules](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/ghci.html#extension-ExtendedDefaultRules)
-- in ghci or switched on as an extension also need to be understood.
-- It can lead to unusual interactions with numerics and strange error messages at times because
-- it adds @()@ and @[]@ to the start of the type defaulting list.

-- $overview
-- numhask is largely a set of classes that can replace the 'GHC.Num.Num' class and it's descendents.
-- Principles that have guided design include:
--
-- - __/balanced class density/__. The numeric hierarchy begins with addition and multiplication,
--   choosing not to build from a Magma base. Whilst not being as principled as other approaches, this circumvents the instance explosion problems of Haskell whilst maintaining clarity of class purpose.
--
-- - __/operator-first/__. In all cases, a class exists to define useful operators.
--   Major class groupings, such as 'Distributive', 'Ring' and 'Field' are type synonyms.
--
-- - __/lawful/__. All classes have laws associated with them that serve to relate class operators together in a meaningful way.
--
-- - __/low-impact/__. The library attempts to fit in with the rest of the Haskell ecosystem.
--   It provides instances for common numbers: 'GHC.Num.Int', 'GHC.Num.Integer', 'GHC.Float.Double',
--   'GHC.Float.Float', 'GHC.Natural.Natural', and the Word classes. It avoids name (or idea) clashes with other popular libraries
--   and adopts conventions in the <https://hackage.haskell.org/package/base/docs/Prelude.html current prelude>
--   where they make sense.
--
-- - __/proof-of-concept/__. The library may be below industrial-strength depending on a definition
--   of this term. At the same time, correspondence around improving the library is most welcome.

-- $pictures
--
-- The class heirarchy looks somewhat like this:
--
-- ![classes](other/nh.svg)

-- $mapping
--
-- 'GHC.Num' is a very old part of haskell, and is virtually unchanged since its specification in
-- [haskell98](https://www.haskell.org/onlinereport/standard-prelude.html).
--
-- A deconstruction of 'GHC.Num.Num' and mapping to numhask.
--
-- > -- | Basic numeric class.
-- > class  Num a  where
-- >    {-# MINIMAL (+), (*), abs, signum, fromInteger, (negate | (-)) #-}
-- >
-- >    (+), (-), (*)       :: a -> a -> a
-- >    -- | Unary negation.
-- >    negate              :: a -> a
--
-- '(+)' is an operator of the 'Additive' class
--
-- '(-)' & 'negate' are functions in the 'Subtractive' class, and
--
-- '(*)' is an operator of the 'Multiplicative' class.
--
-- 'zero' and 'one' are also introduced to the numeric hierarchy.
--
-- >    -- | Absolute value.
-- >    abs                 :: a -> a
-- >    -- | Sign of a number.
-- >    -- The functions 'abs' and 'signum' should satisfy the law:
-- >    --
-- >    -- > abs x * signum x == x
-- >    --
-- >    -- For real numbers, the 'signum' is either @-1@ (negative), @0@ (zero)
-- >    -- or @1@ (positive).
-- >    signum              :: a -> a
--
-- The concept of an absolute value and the sign of a number can include situations where the domain type is different to the absolute and sign codomain types.
--
-- A new class, 'Basis' is supplied to handle these situations:
--
-- - the 'magnitude' method is a generalisation of 'abs'
--
-- - the 'basis' method is a generalisation of 'signum'
--
-- 'NumHask.Algebra.Metric.abs' and 'NumHask.Algebra.Metric.signum' are specialisations of these methods.
--
-- >    -- | Conversion from an 'Integer'.
-- >    -- An integer literal represents the application of the function
-- >    -- 'fromInteger' to the appropriate value of type 'Integer',
-- >    -- so such literals have type @('Num' a) => a@.
-- >    fromInteger         :: Integer -> a
--
-- 'FromInteger' becomes its own class and 'FromIntegral' is introduced to polymorphise the covariant.
--
-- Mappings from other areas of prelude include:
--
-- - 'GHC.Real.Integral' becomes 'Integral' and a polymorphic 'ToIntegral' is introduced.
--
-- - 'GHC.Real.Fractional' is roughly synonymous to 'Field' together with a polymorphic 'FromRatio'.
--
-- - 'GHC.Real.RealFrac' becomes 'QuotientField' with a polymorphic 'Whole' type using Type Families.
--
-- - 'GHC.Float.Floating' is split into 'ExpField' and 'TrigField'
--
-- - 'GHC.Float.RealFloat' is not attempted. Life is too short.
--
-- - Complex is resupplied in 'NumHask.Data.Complex' but with some functionality deriving via 'NumHask.Algebra.Metric.EuclideanPair'. The underlying representation has also been switched to a newtype-wrapped tuple.
--
-- In addition to base changes, alternatives to 'sum' and 'product' from 'Data.Foldable' are also supplied.