{-# language Trustworthy #-}

module NatOptics.Signed
  (
    Signed (..),
    intIso,
    intNatIso,
  )
  where

import Data.Eq            ( Eq )
import Data.Ord           ( Ord, compare, Ordering (..) )
import Numeric.Natural    ( Natural )
import Optics.Core        ( Iso', iso )
import Prelude            ( Integer, abs, negate, fromIntegral )
import Text.Show          ( Show )

import NatOptics.Positive.Unsafe ( Positive (..) )

data Signed n = Zero | Minus (Positive n) | Plus (Positive n)
    deriving stock (Signed n -> Signed n -> Bool
(Signed n -> Signed n -> Bool)
-> (Signed n -> Signed n -> Bool) -> Eq (Signed n)
forall n. Eq n => Signed n -> Signed n -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Signed n -> Signed n -> Bool
$c/= :: forall n. Eq n => Signed n -> Signed n -> Bool
== :: Signed n -> Signed n -> Bool
$c== :: forall n. Eq n => Signed n -> Signed n -> Bool
Eq, Eq (Signed n)
Eq (Signed n)
-> (Signed n -> Signed n -> Ordering)
-> (Signed n -> Signed n -> Bool)
-> (Signed n -> Signed n -> Bool)
-> (Signed n -> Signed n -> Bool)
-> (Signed n -> Signed n -> Bool)
-> (Signed n -> Signed n -> Signed n)
-> (Signed n -> Signed n -> Signed n)
-> Ord (Signed n)
Signed n -> Signed n -> Bool
Signed n -> Signed n -> Ordering
Signed n -> Signed n -> Signed n
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall n. Ord n => Eq (Signed n)
forall n. Ord n => Signed n -> Signed n -> Bool
forall n. Ord n => Signed n -> Signed n -> Ordering
forall n. Ord n => Signed n -> Signed n -> Signed n
min :: Signed n -> Signed n -> Signed n
$cmin :: forall n. Ord n => Signed n -> Signed n -> Signed n
max :: Signed n -> Signed n -> Signed n
$cmax :: forall n. Ord n => Signed n -> Signed n -> Signed n
>= :: Signed n -> Signed n -> Bool
$c>= :: forall n. Ord n => Signed n -> Signed n -> Bool
> :: Signed n -> Signed n -> Bool
$c> :: forall n. Ord n => Signed n -> Signed n -> Bool
<= :: Signed n -> Signed n -> Bool
$c<= :: forall n. Ord n => Signed n -> Signed n -> Bool
< :: Signed n -> Signed n -> Bool
$c< :: forall n. Ord n => Signed n -> Signed n -> Bool
compare :: Signed n -> Signed n -> Ordering
$ccompare :: forall n. Ord n => Signed n -> Signed n -> Ordering
$cp1Ord :: forall n. Ord n => Eq (Signed n)
Ord, Int -> Signed n -> ShowS
[Signed n] -> ShowS
Signed n -> String
(Int -> Signed n -> ShowS)
-> (Signed n -> String) -> ([Signed n] -> ShowS) -> Show (Signed n)
forall n. Show n => Int -> Signed n -> ShowS
forall n. Show n => [Signed n] -> ShowS
forall n. Show n => Signed n -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Signed n] -> ShowS
$cshowList :: forall n. Show n => [Signed n] -> ShowS
show :: Signed n -> String
$cshow :: forall n. Show n => Signed n -> String
showsPrec :: Int -> Signed n -> ShowS
$cshowsPrec :: forall n. Show n => Int -> Signed n -> ShowS
Show)

intIso :: Iso' Integer (Signed Integer)
intIso :: Iso' Integer (Signed Integer)
intIso = (Integer -> Signed Integer)
-> (Signed Integer -> Integer) -> Iso' Integer (Signed Integer)
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso Integer -> Signed Integer
forall n. (Ord n, Num n) => n -> Signed n
f Signed Integer -> Integer
forall a. Num a => Signed a -> a
g
  where
    f :: n -> Signed n
f n
x = case n -> n -> Ordering
forall a. Ord a => a -> a -> Ordering
compare n
x n
0 of
        Ordering
EQ -> Signed n
forall n. Signed n
Zero
        Ordering
LT -> Positive n -> Signed n
forall n. Positive n -> Signed n
Minus (n -> Positive n
forall number. number -> Positive number
PositiveUnsafe (n -> n
forall a. Num a => a -> a
abs n
x))
        Ordering
GT -> Positive n -> Signed n
forall n. Positive n -> Signed n
Plus (n -> Positive n
forall number. number -> Positive number
PositiveUnsafe n
x)
    g :: Signed a -> a
g Signed a
y = case Signed a
y of
        Signed a
Zero -> a
0
        Plus (PositiveUnsafe a
x) -> a
x
        Minus (PositiveUnsafe a
x) -> a -> a
forall a. Num a => a -> a
negate a
x

intNatIso :: Iso' Integer (Signed Natural)
intNatIso :: Iso' Integer (Signed Natural)
intNatIso = (Integer -> Signed Natural)
-> (Signed Natural -> Integer) -> Iso' Integer (Signed Natural)
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso Integer -> Signed Natural
forall a n. (Integral a, Num n) => a -> Signed n
f Signed Natural -> Integer
forall a p. (Integral a, Num p) => Signed a -> p
g
  where
    f :: a -> Signed n
f a
x = case a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
x a
0 of
        Ordering
EQ -> Signed n
forall n. Signed n
Zero
        Ordering
LT -> Positive n -> Signed n
forall n. Positive n -> Signed n
Minus (n -> Positive n
forall number. number -> Positive number
PositiveUnsafe (a -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> a
forall a. Num a => a -> a
abs a
x)))
        Ordering
GT -> Positive n -> Signed n
forall n. Positive n -> Signed n
Plus (n -> Positive n
forall number. number -> Positive number
PositiveUnsafe (a -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
x))
    g :: Signed a -> p
g Signed a
y = case Signed a
y of
        Signed a
Zero -> p
0
        Plus (PositiveUnsafe a
x) -> a -> p
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
x
        Minus (PositiveUnsafe a
x) -> p -> p
forall a. Num a => a -> a
negate (a -> p
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
x)