{-# language Trustworthy #-}

module Integer.Signed
  (
    {- * Type -} Signed (Zero, NonZero, Plus, Minus, NotPlus, NotMinus),
    {- * Conversion -}
    {- ** Integer -} toInteger, fromInteger,
    {- ** Natural -} toNatural, fromNatural,
    {- ** Positive -} toPositive, fromPositive,
    {- ** Int -} toInt, fromInt,
    {- ** Word -} toWord, fromWord,
  )
  where

import Data.Function (($), (.))
import Data.Int (Int)
import Data.Maybe (Maybe (..))
import Data.Word (Word)
import Integer.Positive.Unsafe (Positive)
import Integer.Sign (Sign (..))
import Numeric.Natural (Natural)
import Prelude (Enum, Eq, Integer, Integral, Num, Ord, Real, Show, seq)

import qualified Control.DeepSeq as DeepSeq
import qualified Data.List as List
import qualified Data.Ord as Ord
import qualified Integer.Positive.Unsafe as Positive.Unsafe
import qualified Integer.Sign as Sign
import qualified Prelude as Bounded (Bounded (..))
import qualified Prelude as Enum (Enum (..))
import qualified Prelude as Num (Integral (..), Num (..), Real (..))
import qualified Text.Show as Show

data Signed = Zero | NonZero Sign Positive
    deriving (Signed -> Signed -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Signed -> Signed -> Bool
$c/= :: Signed -> Signed -> Bool
== :: Signed -> Signed -> Bool
$c== :: Signed -> Signed -> Bool
Eq)

instance Ord Signed where
    compare :: Signed -> Signed -> Ordering
compare Signed
Zero Signed
Zero = Ordering
Ord.EQ

    compare Signed
Zero (Minus Positive
_) = Ordering
Ord.GT
    compare Signed
Zero (Plus Positive
_ ) = Ordering
Ord.LT
    compare (Minus Positive
_) Signed
Zero = Ordering
Ord.LT
    compare (Plus  Positive
_) Signed
Zero = Ordering
Ord.GT

    compare (Plus  Positive
_) (Minus Positive
_) = Ordering
Ord.GT
    compare (Minus Positive
_) (Plus  Positive
_) = Ordering
Ord.LT
    compare (Plus  Positive
a) (Plus  Positive
b) = forall a. Ord a => a -> a -> Ordering
Ord.compare Positive
a Positive
b
    compare (Minus Positive
a) (Minus Positive
b) = forall a. Ord a => a -> a -> Ordering
Ord.compare Positive
b Positive
a

instance DeepSeq.NFData Signed where
    rnf :: Signed -> ()
rnf Signed
Zero          = ()
    rnf (NonZero Sign
a Positive
b) = Sign
a seq :: forall a b. a -> b -> b
`seq` Positive
b seq :: forall a b. a -> b -> b
`seq` ()

pattern Minus :: Positive -> Signed
pattern $bMinus :: Positive -> Signed
$mMinus :: forall {r}. Signed -> (Positive -> r) -> ((# #) -> r) -> r
Minus x = NonZero MinusSign x
pattern Plus :: Positive -> Signed

pattern $bPlus :: Positive -> Signed
$mPlus :: forall {r}. Signed -> (Positive -> r) -> ((# #) -> r) -> r
Plus x = NonZero PlusSign x

-- | A 'Signed' that is either zero or positive
pattern NotMinus :: Natural -> Signed
pattern $bNotMinus :: Natural -> Signed
$mNotMinus :: forall {r}. Signed -> (Natural -> r) -> ((# #) -> r) -> r
NotMinus x <- (toNatural -> Just x)
  where NotMinus = Natural -> Signed
fromNatural

-- | A 'Signed' that is either zero or negative;
-- the 'Natural' gives the magnitude of the negative
pattern NotPlus :: Natural -> Signed
pattern $bNotPlus :: Natural -> Signed
$mNotPlus :: forall {r}. Signed -> (Natural -> r) -> ((# #) -> r) -> r
NotPlus x <- ((toNatural . negate) -> Just x)
  where NotPlus = Signed -> Signed
negate forall b c a. (b -> c) -> (a -> b) -> a -> c
. Natural -> Signed
fromNatural

{-# complete Zero, Minus, Plus #-}
{-# complete Plus, NotPlus #-}
{-# complete Minus, NotMinus #-}

fromPositive :: Positive -> Signed
fromPositive :: Positive -> Signed
fromPositive = Positive -> Signed
Plus

toPositive :: Signed -> Maybe Positive
toPositive :: Signed -> Maybe Positive
toPositive (Plus Positive
x) = forall a. a -> Maybe a
Just Positive
x
toPositive Signed
_        = forall a. Maybe a
Nothing

fromNatural :: Natural -> Signed
fromNatural :: Natural -> Signed
fromNatural Natural
0 = Signed
Zero
fromNatural Natural
x = Positive -> Signed
Plus forall a b. (a -> b) -> a -> b
$ Natural -> Positive
Positive.Unsafe.fromNatural Natural
x

toNatural :: Signed -> Maybe Natural
toNatural :: Signed -> Maybe Natural
toNatural (Minus Positive
_) = forall a. Maybe a
Nothing
toNatural Signed
Zero      = forall a. a -> Maybe a
Just Natural
0
toNatural (Plus Positive
x)  = forall a. a -> Maybe a
Just (Positive -> Natural
Positive.Unsafe.toNatural Positive
x)

add :: Signed -> Signed -> Signed
add :: Signed -> Signed -> Signed
add Signed
Zero Signed
x = Signed
x
add Signed
x Signed
Zero = Signed
x
add (NonZero Sign
sa Positive
a) (NonZero Sign
sb Positive
b) = case (Sign
sa, Sign
sb) of
    (Sign
PlusSign, Sign
PlusSign)   -> Positive -> Signed
Plus  forall a b. (a -> b) -> a -> b
$ Positive
a forall a. Num a => a -> a -> a
Num.+ Positive
b
    (Sign
MinusSign, Sign
MinusSign) -> Positive -> Signed
Minus forall a b. (a -> b) -> a -> b
$ Positive
a forall a. Num a => a -> a -> a
Num.+ Positive
b

    (Sign
MinusSign, Sign
PlusSign) -> case forall a. Ord a => a -> a -> Ordering
Ord.compare Positive
a Positive
b of
        Ordering
Ord.EQ -> Signed
Zero
        Ordering
Ord.LT -> Positive -> Signed
Plus  forall a b. (a -> b) -> a -> b
$ Positive -> Positive -> Positive
Positive.Unsafe.subtract Positive
b Positive
a
        Ordering
Ord.GT -> Positive -> Signed
Minus forall a b. (a -> b) -> a -> b
$ Positive -> Positive -> Positive
Positive.Unsafe.subtract Positive
a Positive
b

    (Sign
PlusSign, Sign
MinusSign) -> case forall a. Ord a => a -> a -> Ordering
Ord.compare Positive
a Positive
b of
        Ordering
Ord.EQ -> Signed
Zero
        Ordering
Ord.LT -> Positive -> Signed
Minus forall a b. (a -> b) -> a -> b
$ Positive -> Positive -> Positive
Positive.Unsafe.subtract Positive
b Positive
a
        Ordering
Ord.GT -> Positive -> Signed
Plus  forall a b. (a -> b) -> a -> b
$ Positive -> Positive -> Positive
Positive.Unsafe.subtract Positive
a Positive
b

negate :: Signed -> Signed
negate :: Signed -> Signed
negate Signed
Zero          = Signed
Zero
negate (NonZero Sign
s Positive
x) = Sign -> Positive -> Signed
NonZero (Sign -> Sign
Sign.negate Sign
s) Positive
x

multiply :: Signed -> Signed -> Signed
multiply :: Signed -> Signed -> Signed
multiply Signed
Zero Signed
_ = Signed
Zero
multiply Signed
_ Signed
Zero = Signed
Zero
multiply (NonZero Sign
sa Positive
a) (NonZero Sign
sb Positive
b) =
    Sign -> Positive -> Signed
NonZero (Sign -> Sign -> Sign
Sign.multiply Sign
sa Sign
sb) (Positive
a forall a. Num a => a -> a -> a
Num.* Positive
b)

abs :: Signed -> Signed
abs :: Signed -> Signed
abs Signed
Zero = Signed
Zero
abs x :: Signed
x@(NonZero Sign
s Positive
p) = case Sign
s of
    Sign
PlusSign  -> Signed
x
    Sign
MinusSign -> Sign -> Positive -> Signed
NonZero Sign
PlusSign Positive
p

signum :: Signed -> Signed
signum :: Signed -> Signed
signum Signed
Zero          = Signed
Zero
signum (NonZero Sign
s Positive
_) = Sign -> Positive -> Signed
NonZero Sign
s Positive
Positive.Unsafe.one

fromInteger :: Integer -> Signed
fromInteger :: Integer -> Signed
fromInteger Integer
x = case forall a. Ord a => a -> a -> Ordering
Ord.compare Integer
x Integer
0 of
    Ordering
Ord.EQ -> Signed
Zero
    Ordering
Ord.LT -> Positive -> Signed
Minus forall a b. (a -> b) -> a -> b
$ Integer -> Positive
Positive.Unsafe.fromInteger forall a b. (a -> b) -> a -> b
$ forall a. Num a => a -> a
Num.abs Integer
x
    Ordering
Ord.GT -> Positive -> Signed
Plus  forall a b. (a -> b) -> a -> b
$ Integer -> Positive
Positive.Unsafe.fromInteger Integer
x

toInteger :: Signed -> Integer
toInteger :: Signed -> Integer
toInteger Signed
Zero      = Integer
0
toInteger (Plus Positive
x)  = Positive -> Integer
Positive.Unsafe.toInteger Positive
x
toInteger (Minus Positive
x) = forall a. Num a => a -> a
Num.negate forall a b. (a -> b) -> a -> b
$ Positive -> Integer
Positive.Unsafe.toInteger Positive
x

toInt :: Signed -> Maybe Int
toInt :: Signed -> Maybe Int
toInt Signed
x = case Signed
x of
    Signed
Zero -> forall a. a -> Maybe a
Just Int
0
    Plus Positive
p -> if Bool
ok then forall a. a -> Maybe a
Just (forall a. Num a => Integer -> a
Num.fromInteger Integer
i) else forall a. Maybe a
Nothing
      where
        ok :: Bool
ok = Integer
i forall a. Ord a => a -> a -> Bool
Ord.<= forall a. Integral a => a -> Integer
Num.toInteger (forall a. Bounded a => a
Bounded.maxBound :: Int)
        i :: Integer
i = Positive -> Integer
Positive.Unsafe.toInteger Positive
p
    Minus Positive
p -> if Bool
ok then forall a. a -> Maybe a
Just (forall a. Num a => Integer -> a
Num.fromInteger Integer
i) else forall a. Maybe a
Nothing
      where
        ok :: Bool
ok = Integer
i forall a. Ord a => a -> a -> Bool
Ord.>= forall a. Integral a => a -> Integer
Num.toInteger (forall a. Bounded a => a
Bounded.minBound :: Int)
        i :: Integer
i = forall a. Num a => a -> a
Num.negate (Positive -> Integer
Positive.Unsafe.toInteger Positive
p)

fromInt :: Int -> Signed
fromInt :: Int -> Signed
fromInt Int
x = case forall a. Ord a => a -> a -> Ordering
Ord.compare Int
x Int
0 of
    Ordering
Ord.EQ -> Signed
Zero
    Ordering
Ord.GT -> Positive -> Signed
Plus forall a b. (a -> b) -> a -> b
$ Int -> Positive
Positive.Unsafe.fromInt Int
x
    Ordering
Ord.LT -> Positive -> Signed
Minus forall a b. (a -> b) -> a -> b
$ Integer -> Positive
Positive.Unsafe.fromInteger forall a b. (a -> b) -> a -> b
$ forall a. Num a => a -> a
Num.negate forall a b. (a -> b) -> a -> b
$ forall a. Integral a => a -> Integer
Num.toInteger Int
x

toWord :: Signed -> Maybe Word
toWord :: Signed -> Maybe Word
toWord Signed
x = case Signed
x of
    Signed
Zero -> forall a. a -> Maybe a
Just Word
0
    Plus Positive
p -> if Bool
ok then forall a. a -> Maybe a
Just (forall a. Num a => Integer -> a
Num.fromInteger Integer
i) else forall a. Maybe a
Nothing
      where
        ok :: Bool
ok = Integer
i forall a. Ord a => a -> a -> Bool
Ord.<= forall a. Integral a => a -> Integer
Num.toInteger (forall a. Bounded a => a
Bounded.maxBound :: Word)
        i :: Integer
i = Positive -> Integer
Positive.Unsafe.toInteger Positive
p
    Minus Positive
_ -> forall a. Maybe a
Nothing

fromWord :: Word -> Signed
fromWord :: Word -> Signed
fromWord Word
x = case Word
x of
    Word
0 -> Signed
Zero
    Word
_ -> Positive -> Signed
Plus forall a b. (a -> b) -> a -> b
$ Integer -> Positive
Positive.Unsafe.fromInteger (forall a. Integral a => a -> Integer
Num.toInteger Word
x)

type Div a = a -> a -> (a, a)

divisionOp :: Div Integer -> Div Signed
divisionOp :: Div Integer -> Div Signed
divisionOp Div Integer
o Signed
a Signed
b =
    let (Integer
q, Integer
r) = Div Integer
o (Signed -> Integer
toInteger Signed
a) (Signed -> Integer
toInteger Signed
b)
    in (Integer -> Signed
fromInteger Integer
q, Integer -> Signed
fromInteger Integer
r)

instance Num Signed
  where
    + :: Signed -> Signed -> Signed
(+) = Signed -> Signed -> Signed
add
    * :: Signed -> Signed -> Signed
(*) = Signed -> Signed -> Signed
multiply
    negate :: Signed -> Signed
negate = Signed -> Signed
negate
    abs :: Signed -> Signed
abs = Signed -> Signed
abs
    signum :: Signed -> Signed
signum = Signed -> Signed
signum
    fromInteger :: Integer -> Signed
fromInteger = Integer -> Signed
fromInteger

instance Enum Signed
  where
    pred :: Signed -> Signed
pred = Integer -> Signed
fromInteger forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Enum a => a -> a
Enum.pred forall b c a. (b -> c) -> (a -> b) -> a -> c
. Signed -> Integer
toInteger
    succ :: Signed -> Signed
succ = Integer -> Signed
fromInteger forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Enum a => a -> a
Enum.succ forall b c a. (b -> c) -> (a -> b) -> a -> c
. Signed -> Integer
toInteger

    toEnum :: Int -> Signed
toEnum = Integer -> Signed
fromInteger forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Enum a => Int -> a
Enum.toEnum
    fromEnum :: Signed -> Int
fromEnum = forall a. Enum a => a -> Int
Enum.fromEnum forall b c a. (b -> c) -> (a -> b) -> a -> c
. Signed -> Integer
toInteger

    enumFrom :: Signed -> [Signed]
enumFrom Signed
a = forall a b. (a -> b) -> [a] -> [b]
List.map Integer -> Signed
fromInteger forall a b. (a -> b) -> a -> b
$ forall a. Enum a => a -> [a]
Enum.enumFrom (Signed -> Integer
toInteger Signed
a)
    enumFromTo :: Signed -> Signed -> [Signed]
enumFromTo Signed
a Signed
b = forall a b. (a -> b) -> [a] -> [b]
List.map Integer -> Signed
fromInteger forall a b. (a -> b) -> a -> b
$ forall a. Enum a => a -> a -> [a]
Enum.enumFromTo (Signed -> Integer
toInteger Signed
a) (Signed -> Integer
toInteger Signed
b)
    enumFromThen :: Signed -> Signed -> [Signed]
enumFromThen Signed
a Signed
b = forall a b. (a -> b) -> [a] -> [b]
List.map Integer -> Signed
fromInteger forall a b. (a -> b) -> a -> b
$ forall a. Enum a => a -> a -> [a]
Enum.enumFromThen (Signed -> Integer
toInteger Signed
a) (Signed -> Integer
toInteger Signed
b)
    enumFromThenTo :: Signed -> Signed -> Signed -> [Signed]
enumFromThenTo Signed
a Signed
b Signed
c = forall a b. (a -> b) -> [a] -> [b]
List.map Integer -> Signed
fromInteger forall a b. (a -> b) -> a -> b
$ forall a. Enum a => a -> a -> a -> [a]
Enum.enumFromThenTo (Signed -> Integer
toInteger Signed
a) (Signed -> Integer
toInteger Signed
b) (Signed -> Integer
toInteger Signed
c)

instance Real Signed
  where
    toRational :: Signed -> Rational
toRational = forall a. Real a => a -> Rational
Num.toRational forall b c a. (b -> c) -> (a -> b) -> a -> c
. Signed -> Integer
toInteger

instance Integral Signed
  where
    toInteger :: Signed -> Integer
toInteger = Signed -> Integer
toInteger
    quotRem :: Div Signed
quotRem = Div Integer -> Div Signed
divisionOp forall a. Integral a => a -> a -> (a, a)
Num.quotRem
    divMod :: Div Signed
divMod = Div Integer -> Div Signed
divisionOp forall a. Integral a => a -> a -> (a, a)
Num.divMod

instance Show Signed
  where
    show :: Signed -> String
show = forall a. Show a => a -> String
Show.show forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Integral a => a -> Integer
Num.toInteger
    showsPrec :: Int -> Signed -> ShowS
showsPrec Int
i = forall a. Show a => Int -> a -> ShowS
Show.showsPrec Int
i forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Integral a => a -> Integer
Num.toInteger