    -- |
    -- Module:      Math.NumberTheory.Moduli.Class
    -- Copyright:   (c) 2017 Andrew Lelechenko
    -- Licence:     MIT
    -- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>
    --
    -- Safe modular arithmetic with modulo on type level.
    --

    {-# LANGUAGE DataKinds                  #-}
    {-# LANGUAGE GADTs                      #-}
    {-# LANGUAGE KindSignatures             #-}
    {-# LANGUAGE RankNTypes                 #-}
    {-# LANGUAGE ScopedTypeVariables        #-}

    module Math.NumberTheory.Moduli.Class
      ( -- * Known modulo
        Mod
      , getVal
      , getNatVal
      , getMod
      , getNatMod
      , invertMod
      , powMod
      , (^%)
      -- * Multiplicative group
      , MultMod
      , multElement
      , isMultElement
      , invertGroup
      -- * Unknown modulo
      , SomeMod(..)
      , modulo
      , invertSomeMod
      , powSomeMod
      -- * Re-exported from GHC.TypeNats.Compat
      , KnownNat
      ) where

    import Data.Mod
    import GHC.Natural
    import GHC.TypeNats (KnownNat, natVal)

    import Math.NumberTheory.Moduli.Multiplicative
    import Math.NumberTheory.Moduli.SomeMod

    -- | Linking type and value levels: extract modulo @m@ as a value.
    getMod :: KnownNat m => Mod m -> Integer
    getMod :: forall (m :: Nat). KnownNat m => Mod m -> Integer
    getMod = Nat -> Integer
    forall a. Integral a => a -> Integer
    toInteger (Nat -> Integer) -> (Mod m -> Nat) -> Mod m -> Integer
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Mod m -> Nat
    forall (n :: Nat) (proxy :: Nat -> *). KnownNat n => proxy n -> Nat
    natVal
    {-# INLINE getMod #-}

    -- | Linking type and value levels: extract modulo @m@ as a value.
    getNatMod :: KnownNat m => Mod m -> Natural
    getNatMod :: forall (m :: Nat). KnownNat m => Mod m -> Nat
    getNatMod = Mod m -> Nat
    forall (n :: Nat) (proxy :: Nat -> *). KnownNat n => proxy n -> Nat
    natVal
    {-# INLINE getNatMod #-}

    -- | The canonical representative of the residue class, always between 0 and m-1 inclusively.
    getVal :: Mod m -> Integer
    getVal :: forall (m :: Nat). Mod m -> Integer
    getVal = Nat -> Integer
    forall a. Integral a => a -> Integer
    toInteger (Nat -> Integer) -> (Mod m -> Nat) -> Mod m -> Integer
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Mod m -> Nat
    forall (m :: Nat). Mod m -> Nat
    unMod
    {-# INLINE getVal #-}

    -- | The canonical representative of the residue class, always between 0 and m-1 inclusively.
    getNatVal :: Mod m -> Natural
    getNatVal :: forall (m :: Nat). Mod m -> Nat
    getNatVal = Mod m -> Nat
    forall (m :: Nat). Mod m -> Nat
    unMod
    {-# INLINE getNatVal #-}

    -- | Synonym of '(^%)'.
    powMod :: (KnownNat m, Integral a) => Mod m -> a -> Mod m
    powMod :: forall (m :: Nat) a.
    (KnownNat m, Integral a) =>
    Mod m -> a -> Mod m
    powMod = Mod m -> a -> Mod m
    forall (m :: Nat) a.
    (KnownNat m, Integral a) =>
    Mod m -> a -> Mod m
    (^%)
    {-# INLINE powMod #-}