{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
module Basement.Bounded
( Zn64
, unZn64
, Zn
, unZn
, zn64
, zn
, zn64Nat
, znNat
) where
import GHC.TypeLits
import Data.Word
import Basement.Compat.Base
import Basement.Compat.Natural
import Basement.Numerical.Number
import Data.Proxy
import Basement.Nat
import qualified Prelude
newtype Zn64 (n :: Nat) = Zn64 { unZn64 :: Word64 }
deriving (Show,Eq,Ord)
instance (KnownNat n, NatWithinBound Word64 n) => Prelude.Num (Zn64 n) where
fromInteger = zn64 . Prelude.fromInteger
(+) = add64
(-) = sub64
(*) = mul64
abs a = a
negate _ = error "cannot negate Zn64: use Foundation Numerical hierarchy for this function to not be exposed to Zn64"
signum (Zn64 a) = Zn64 (Prelude.signum a)
type instance NatNumMaxBound (Zn64 n) = n
instance (KnownNat n, NatWithinBound Word64 n) => Integral (Zn64 n) where
fromInteger = zn64 . Prelude.fromInteger
instance (KnownNat n, NatWithinBound Word64 n) => IsIntegral (Zn64 n) where
toInteger (Zn64 n) = toInteger n
instance (KnownNat n, NatWithinBound Word64 n) => IsNatural (Zn64 (n :: Nat)) where
toNatural (Zn64 n) = toNatural n
zn64 :: forall n . (KnownNat n, NatWithinBound Word64 n) => Word64 -> Zn64 n
zn64 v = Zn64 (v `Prelude.mod` natValWord64 (Proxy :: Proxy n))
zn64Nat :: forall m n . (KnownNat m, KnownNat n, NatWithinBound Word64 m, NatWithinBound Word64 n, CmpNat m n ~ 'LT)
=> Proxy m
-> Zn64 n
zn64Nat p = Zn64 (natValWord64 p)
add64 :: forall n . (KnownNat n, NatWithinBound Word64 n) => Zn64 n -> Zn64 n -> Zn64 n
add64 (Zn64 a) (Zn64 b) = Zn64 ((a Prelude.+ b) `Prelude.mod` natValWord64 (Proxy :: Proxy n))
sub64 :: forall n . (KnownNat n, NatWithinBound Word64 n) => Zn64 n -> Zn64 n -> Zn64 n
sub64 (Zn64 a) (Zn64 b) = Zn64 ((a Prelude.- b) `Prelude.mod` natValWord64 (Proxy :: Proxy n))
mul64 :: forall n . (KnownNat n, NatWithinBound Word64 n) => Zn64 n -> Zn64 n -> Zn64 n
mul64 (Zn64 a) (Zn64 b) = Zn64 ((a Prelude.* b) `Prelude.mod` natValWord64 (Proxy :: Proxy n))
newtype Zn (n :: Nat) = Zn { unZn :: Natural }
deriving (Show,Eq,Ord)
instance KnownNat n => Prelude.Num (Zn n) where
fromInteger = zn . Prelude.fromInteger
(+) = add
(-) = sub
(*) = mul
abs a = a
negate _ = error "cannot negate Zn: use Foundation Numerical hierarchy for this function to not be exposed to Zn"
signum = Zn . Prelude.signum . unZn
type instance NatNumMaxBound (Zn n) = n
instance KnownNat n => Integral (Zn n) where
fromInteger = zn . Prelude.fromInteger
instance KnownNat n => IsIntegral (Zn n) where
toInteger (Zn n) = toInteger n
instance KnownNat n => IsNatural (Zn n) where
toNatural i = unZn i
zn :: forall n . KnownNat n => Natural -> Zn n
zn v = Zn (v `Prelude.mod` natValNatural (Proxy :: Proxy n))
znNat :: forall m n . (KnownNat m, KnownNat n, CmpNat m n ~ 'LT) => Proxy m -> Zn n
znNat m = Zn (natValNatural m)
add :: forall n . KnownNat n => Zn n -> Zn n -> Zn n
add (Zn a) (Zn b) = Zn ((a Prelude.+ b) `Prelude.mod` natValNatural (Proxy :: Proxy n))
sub :: forall n . KnownNat n => Zn n -> Zn n -> Zn n
sub (Zn a) (Zn b) = Zn ((a Prelude.- b) `Prelude.mod` natValNatural (Proxy :: Proxy n))
mul :: forall n . KnownNat n => Zn n -> Zn n -> Zn n
mul (Zn a) (Zn b) = Zn ((a Prelude.* b) `Prelude.mod` natValNatural (Proxy :: Proxy n))