stellar-veritas/bundled/Basement/Bounded.hs
2026-01-25 02:27:22 +01:00

132 lines
4.5 KiB
Haskell
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE NoImplicitPrelude #-}
-- |
-- Module : Basement.Block
-- License : BSD-style
-- Maintainer : Haskell Foundation
--
-- Types to represent /n.
--
-- /n is a finite field and is defined as the set of natural number:
-- {0, 1, ..., n 1}.
--
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
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
-- | A type level bounded natural backed by a Word64
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
-- | Create an element of /n from a Word64
--
-- If the value is greater than n, then the value is normalized by using the
-- integer modulus n
zn64 :: forall n . (KnownNat n, NatWithinBound Word64 n) => Word64 -> Zn64 n
zn64 v = Zn64 (v `Prelude.mod` natValWord64 (Proxy :: Proxy n))
-- | Create an element of /n from a type level Nat
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)
-- | Add 2 Zn64
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))
-- | subtract 2 Zn64
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))
-- | Multiply 2 Zn64
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))
-- | A type level bounded natural
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
-- | Create an element of /n from a Natural.
--
-- If the value is greater than n, then the value is normalized by using the
-- integer modulus n
zn :: forall n . KnownNat n => Natural -> Zn n
zn v = Zn (v `Prelude.mod` natValNatural (Proxy :: Proxy n))
-- | Create an element of /n from a type level Nat
znNat :: forall m n . (KnownNat m, KnownNat n, CmpNat m n ~ 'LT) => Proxy m -> Zn n
znNat m = Zn (natValNatural m)
-- | Add 2 Zn
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))
-- | subtract 2 Zn
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))
-- | Multiply 2 Zn
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))