{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE LambdaCase #-}
{-# OPTIONS_GHC -Wno-orphans #-}

module Data.Function.FastMemo.Integer () where

import Data.Function.FastMemo.Class (Memoizable (..))
import Data.Function.FastMemo.Natural ()
import GHC.Generics (Generic)
import Numeric.Natural (Natural)

instance Memoizable Integer where
  memoize :: (Integer -> b) -> Integer -> b
memoize Integer -> b
f = ((Sign, Natural) -> b) -> (Sign, Natural) -> b
forall a b. Memoizable a => (a -> b) -> a -> b
memoize (Integer -> b
f (Integer -> b)
-> ((Sign, Natural) -> Integer) -> (Sign, Natural) -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Sign, Natural) -> Integer
signedNatToInteger) ((Sign, Natural) -> b)
-> (Integer -> (Sign, Natural)) -> Integer -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> (Sign, Natural)
integerToSignedNat

data Sign = NegativePlus1 | NonNegative
  deriving ((forall x. Sign -> Rep Sign x)
-> (forall x. Rep Sign x -> Sign) -> Generic Sign
forall x. Rep Sign x -> Sign
forall x. Sign -> Rep Sign x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Sign x -> Sign
$cfrom :: forall x. Sign -> Rep Sign x
Generic, (forall b. (Sign -> b) -> Sign -> b) -> Memoizable Sign
forall b. (Sign -> b) -> Sign -> b
forall a. (forall b. (a -> b) -> a -> b) -> Memoizable a
memoize :: (Sign -> b) -> Sign -> b
$cmemoize :: forall b. (Sign -> b) -> Sign -> b
Memoizable)

integerToSignedNat :: Integer -> (Sign, Natural)
integerToSignedNat :: Integer -> (Sign, Natural)
integerToSignedNat Integer
i
  | Integer
i Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
0 = (Sign
NegativePlus1, Integer -> Natural
forall a. Num a => Integer -> a
fromInteger (- (Integer
i Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
1)))
  | Bool
otherwise = (Sign
NonNegative, Integer -> Natural
forall a. Num a => Integer -> a
fromInteger Integer
i)

signedNatToInteger :: (Sign, Natural) -> Integer
signedNatToInteger :: (Sign, Natural) -> Integer
signedNatToInteger = \case
  (Sign
NegativePlus1, Natural
n) -> - (Natural -> Integer
forall a. Integral a => a -> Integer
toInteger Natural
n Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
1)
  (Sign
NonNegative, Natural
n) -> Natural -> Integer
forall a. Integral a => a -> Integer
toInteger Natural
n