    -- |
    -- Module      : Foundation.Numerical
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : portable
    --
    -- Compared to the Haskell hierarchy of number classes
    -- this provide a more flexible approach that is closer to the
    -- mathematical foundation (group, field, etc)
    --
    -- This try to only provide one feature per class, at the expense of
    -- the number of classes.
    --
    {-# LANGUAGE TypeFamilies #-}
    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE TypeSynonymInstances #-}
    module Foundation.Numerical
        ( IsIntegral(..)
        , IsNatural(..)
        , Signed(..)
        , Additive(..)
        , Subtractive(..)
        , Multiplicative(..)
        , IDivisible(..)
        , Divisible(..)
        , Sign(..)
        , recip
        , IntegralRounding(..)
        , FloatingPoint(..)
        ) where

    import           Basement.Compat.Base
    import           Basement.Numerical.Number
    import           Basement.Numerical.Additive
    import           Basement.Numerical.Subtractive
    import           Basement.Numerical.Multiplicative
    import           Foundation.Numerical.Floating
    import qualified Prelude

    -- | Sign of a signed number
    data Sign = SignNegative | SignZero | SignPositive
        deriving (Sign -> Sign -> Bool
    (Sign -> Sign -> Bool) -> (Sign -> Sign -> Bool) -> Eq Sign
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Sign -> Sign -> Bool
    == :: Sign -> Sign -> Bool
    $c/= :: Sign -> Sign -> Bool
    /= :: Sign -> Sign -> Bool
    Eq)

    orderingToSign :: Ordering -> Sign
    orderingToSign :: Ordering -> Sign
    orderingToSign Ordering
    EQ = Sign
    SignZero
    orderingToSign Ordering
    GT = Sign
    SignNegative
    orderingToSign Ordering
    LT = Sign
    SignPositive

    -- | types that have sign and can be made absolute
    class Signed a where
        {-# MINIMAL abs, signum #-}
        abs    :: a -> a
        signum :: a -> Sign

    instance Signed Integer where
        abs :: Integer -> Integer
    abs = Integer -> Integer
    forall a. Num a => a -> a
    Prelude.abs
        signum :: Integer -> Sign
    signum = Ordering -> Sign
    orderingToSign (Ordering -> Sign) -> (Integer -> Ordering) -> Integer -> Sign
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Integer -> Integer -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare Integer
    0
    instance Signed Int where
        abs :: Int -> Int
    abs = Int -> Int
    forall a. Num a => a -> a
    Prelude.abs
        signum :: Int -> Sign
    signum = Ordering -> Sign
    orderingToSign (Ordering -> Sign) -> (Int -> Ordering) -> Int -> Sign
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Int -> Int -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare Int
    0
    instance Signed Int8 where
        abs :: Int8 -> Int8
    abs = Int8 -> Int8
    forall a. Num a => a -> a
    Prelude.abs
        signum :: Int8 -> Sign
    signum = Ordering -> Sign
    orderingToSign (Ordering -> Sign) -> (Int8 -> Ordering) -> Int8 -> Sign
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Int8 -> Int8 -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare Int8
    0
    instance Signed Int16 where
        abs :: Int16 -> Int16
    abs = Int16 -> Int16
    forall a. Num a => a -> a
    Prelude.abs
        signum :: Int16 -> Sign
    signum = Ordering -> Sign
    orderingToSign (Ordering -> Sign) -> (Int16 -> Ordering) -> Int16 -> Sign
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Int16 -> Int16 -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare Int16
    0
    instance Signed Int32 where
        abs :: Int32 -> Int32
    abs = Int32 -> Int32
    forall a. Num a => a -> a
    Prelude.abs
        signum :: Int32 -> Sign
    signum = Ordering -> Sign
    orderingToSign (Ordering -> Sign) -> (Int32 -> Ordering) -> Int32 -> Sign
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Int32 -> Int32 -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare Int32
    0
    instance Signed Int64 where
        abs :: Int64 -> Int64
    abs = Int64 -> Int64
    forall a. Num a => a -> a
    Prelude.abs
        signum :: Int64 -> Sign
    signum = Ordering -> Sign
    orderingToSign (Ordering -> Sign) -> (Int64 -> Ordering) -> Int64 -> Sign
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Int64 -> Int64 -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare Int64
    0
    instance Signed Float where
        abs :: Float -> Float
    abs = Float -> Float
    forall a. Num a => a -> a
    Prelude.abs
        signum :: Float -> Sign
    signum = Ordering -> Sign
    orderingToSign (Ordering -> Sign) -> (Float -> Ordering) -> Float -> Sign
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Float -> Float -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare Float
    0
    instance Signed Double where
        abs :: Double -> Double
    abs = Double -> Double
    forall a. Num a => a -> a
    Prelude.abs
        signum :: Double -> Sign
    signum = Ordering -> Sign
    orderingToSign (Ordering -> Sign) -> (Double -> Ordering) -> Double -> Sign
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Double -> Double -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare Double
    0

    class IntegralRounding a where
        -- | Round up, to the next integral.
        --
        -- Also known as 'ceiling'
        roundUp       :: Integral n => a -> n

        -- | Round down, to the previous integral
        --
        -- Also known as 'floor'
        roundDown     :: Integral n => a -> n

        -- | Truncate to the closest integral to the fractional number
        -- closer to 0.
        --
        -- This is equivalent to roundUp for negative Number
        -- and roundDown for positive Number
        roundTruncate :: Integral n => a -> n

        -- | Round to the nearest integral
        --
        -- > roundNearest 3.6
        -- 4
        -- > roundNearest 3.4
        -- 3
        roundNearest  :: Integral n => a -> n

    instance IntegralRounding Prelude.Rational where
        roundUp :: forall n. Integral n => Rational -> n
    roundUp       = Integer -> n
    forall a. Integral a => Integer -> a
    fromInteger (Integer -> n) -> (Rational -> Integer) -> Rational -> n
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Rational -> Integer
    forall b. Integral b => Rational -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    Prelude.ceiling
        roundDown :: forall n. Integral n => Rational -> n
    roundDown     = Integer -> n
    forall a. Integral a => Integer -> a
    fromInteger (Integer -> n) -> (Rational -> Integer) -> Rational -> n
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Rational -> Integer
    forall b. Integral b => Rational -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    Prelude.floor
        roundTruncate :: forall n. Integral n => Rational -> n
    roundTruncate = Integer -> n
    forall a. Integral a => Integer -> a
    fromInteger (Integer -> n) -> (Rational -> Integer) -> Rational -> n
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Rational -> Integer
    forall b. Integral b => Rational -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    Prelude.truncate
        roundNearest :: forall n. Integral n => Rational -> n
    roundNearest  = Integer -> n
    forall a. Integral a => Integer -> a
    fromInteger (Integer -> n) -> (Rational -> Integer) -> Rational -> n
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Rational -> Integer
    forall b. Integral b => Rational -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    Prelude.round

    instance IntegralRounding Prelude.Double where
        roundUp :: forall n. Integral n => Double -> n
    roundUp       = Integer -> n
    forall a. Integral a => Integer -> a
    fromInteger (Integer -> n) -> (Double -> Integer) -> Double -> n
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Double -> Integer
    forall b. Integral b => Double -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    Prelude.ceiling
        roundDown :: forall n. Integral n => Double -> n
    roundDown     = Integer -> n
    forall a. Integral a => Integer -> a
    fromInteger (Integer -> n) -> (Double -> Integer) -> Double -> n
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Double -> Integer
    forall b. Integral b => Double -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    Prelude.floor
        roundTruncate :: forall n. Integral n => Double -> n
    roundTruncate = Integer -> n
    forall a. Integral a => Integer -> a
    fromInteger (Integer -> n) -> (Double -> Integer) -> Double -> n
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Double -> Integer
    forall b. Integral b => Double -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    Prelude.truncate
        roundNearest :: forall n. Integral n => Double -> n
    roundNearest  = Integer -> n
    forall a. Integral a => Integer -> a
    fromInteger (Integer -> n) -> (Double -> Integer) -> Double -> n
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Double -> Integer
    forall b. Integral b => Double -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    Prelude.round

    instance IntegralRounding Prelude.Float where
        roundUp :: forall n. Integral n => Float -> n
    roundUp       = Integer -> n
    forall a. Integral a => Integer -> a
    fromInteger (Integer -> n) -> (Float -> Integer) -> Float -> n
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Float -> Integer
    forall b. Integral b => Float -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    Prelude.ceiling
        roundDown :: forall n. Integral n => Float -> n
    roundDown     = Integer -> n
    forall a. Integral a => Integer -> a
    fromInteger (Integer -> n) -> (Float -> Integer) -> Float -> n
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Float -> Integer
    forall b. Integral b => Float -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    Prelude.floor
        roundTruncate :: forall n. Integral n => Float -> n
    roundTruncate = Integer -> n
    forall a. Integral a => Integer -> a
    fromInteger (Integer -> n) -> (Float -> Integer) -> Float -> n
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Float -> Integer
    forall b. Integral b => Float -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    Prelude.truncate
        roundNearest :: forall n. Integral n => Float -> n
    roundNearest  = Integer -> n
    forall a. Integral a => Integer -> a
    fromInteger (Integer -> n) -> (Float -> Integer) -> Float -> n
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . Float -> Integer
    forall b. Integral b => Float -> b
    forall a b. (RealFrac a, Integral b) => a -> b
    Prelude.round