finite-typelits 0.1.6.0 → 0.2.0.0
raw patch · 6 files changed
+2079/−743 lines, 6 filesdep +taggeddep +template-haskelldep ~QuickCheckdep ~basedep ~deepseqPVP ok
version bump matches the API change (PVP)
Dependencies added: tagged, template-haskell
Dependency ranges changed: QuickCheck, base, deepseq
API changes (from Hackage documentation)
- Data.Finite: data Finite (n :: Nat)
- Data.Finite.Internal: Finite :: Integer -> Finite (n :: Nat)
- Data.Finite.Internal: instance Control.DeepSeq.NFData (Data.Finite.Internal.Finite n)
- Data.Finite.Internal: instance GHC.Classes.Eq (Data.Finite.Internal.Finite n)
- Data.Finite.Internal: instance GHC.Classes.Ord (Data.Finite.Internal.Finite n)
- Data.Finite.Internal: instance GHC.Generics.Generic (Data.Finite.Internal.Finite n)
- Data.Finite.Internal: instance GHC.Show.Show (Data.Finite.Internal.Finite n)
- Data.Finite.Internal: instance GHC.TypeNats.KnownNat n => GHC.Enum.Bounded (Data.Finite.Internal.Finite n)
- Data.Finite.Internal: instance GHC.TypeNats.KnownNat n => GHC.Enum.Enum (Data.Finite.Internal.Finite n)
- Data.Finite.Internal: instance GHC.TypeNats.KnownNat n => GHC.Num.Num (Data.Finite.Internal.Finite n)
- Data.Finite.Internal: instance GHC.TypeNats.KnownNat n => GHC.Read.Read (Data.Finite.Internal.Finite n)
- Data.Finite.Internal: instance GHC.TypeNats.KnownNat n => GHC.Real.Integral (Data.Finite.Internal.Finite n)
- Data.Finite.Internal: instance GHC.TypeNats.KnownNat n => GHC.Real.Real (Data.Finite.Internal.Finite n)
- Data.Finite.Internal: newtype Finite (n :: Nat)
+ Data.Finite: combineExponential :: forall n m. (KnownNat m, KnownNat n) => (Finite n -> Finite m) -> Finite (m ^ n)
+ Data.Finite: combineOne :: () -> Finite 1
+ Data.Finite: combineZero :: Void -> Finite 0
+ Data.Finite: separateExponential :: forall n m. KnownNat m => Finite (m ^ n) -> Finite n -> Finite m
+ Data.Finite: separateOne :: Finite 1 -> ()
+ Data.Finite: separateZero :: Finite 0 -> Void
+ Data.Finite: type Finite = Finite Integer
+ Data.Finite.Integral: add :: forall n m a. (SaneIntegral a, Limited a (n + m)) => Finite a n -> Finite a m -> Finite a (n + m)
+ Data.Finite.Integral: class KnownIntegral a (n :: Nat)
+ Data.Finite.Integral: class Integral a => SaneIntegral a
+ Data.Finite.Integral: cmp :: forall n m a. Ord a => Finite a n -> Finite a m -> Ordering
+ Data.Finite.Integral: combineExponential :: forall n m a. (SaneIntegral a, KnownIntegral a m, KnownIntegral a n, Limited a (m ^ n)) => (Finite a n -> Finite a m) -> Finite a (m ^ n)
+ Data.Finite.Integral: combineOne :: forall a. (SaneIntegral a, Limited a 1) => () -> Finite a 1
+ Data.Finite.Integral: combineProduct :: forall n m a. (SaneIntegral a, KnownIntegral a n, Limited a (n * m)) => (Finite a n, Finite a m) -> Finite a (n * m)
+ Data.Finite.Integral: combineSum :: forall n m a. (SaneIntegral a, KnownIntegral a n, Limited a (n + m)) => Either (Finite a n) (Finite a m) -> Finite a (n + m)
+ Data.Finite.Integral: combineZero :: forall a. Void -> Finite a 0
+ Data.Finite.Integral: data Finite a (n :: Nat)
+ Data.Finite.Integral: equals :: forall n m a. Eq a => Finite a n -> Finite a m -> Bool
+ Data.Finite.Integral: finite :: forall n a. (SaneIntegral a, KnownIntegral a n) => a -> Finite a n
+ Data.Finite.Integral: finiteProxy :: forall n a proxy. (SaneIntegral a, KnownIntegral a n) => proxy n -> a -> Finite a n
+ Data.Finite.Integral: finites :: forall n a. (SaneIntegral a, KnownIntegral a n) => [Finite a n]
+ Data.Finite.Integral: finitesProxy :: forall n a proxy. (SaneIntegral a, KnownIntegral a n) => proxy n -> [Finite a n]
+ Data.Finite.Integral: getFinite :: forall n a. Finite a n -> a
+ Data.Finite.Integral: infix 4 `equals`
+ Data.Finite.Integral: intVal :: forall n a proxy. KnownIntegral a n => proxy n -> a
+ Data.Finite.Integral: isValidFinite :: forall n a. (Ord a, Num a, KnownIntegral a n) => Finite a n -> Bool
+ Data.Finite.Integral: modulo :: forall n a. (SaneIntegral a, KnownIntegral a n) => a -> Finite a n
+ Data.Finite.Integral: moduloProxy :: forall n a proxy. (SaneIntegral a, KnownIntegral a n) => proxy n -> a -> Finite a n
+ Data.Finite.Integral: multiply :: forall n m a. (SaneIntegral a, Limited a (n * m)) => Finite a n -> Finite a m -> Finite a (n * m)
+ Data.Finite.Integral: natToFinite :: forall n m a proxy. (SaneIntegral a, KnownIntegral a n, Limited a m, (n + 1) <= m) => proxy n -> Finite a m
+ Data.Finite.Integral: packFinite :: forall n a. (SaneIntegral a, KnownIntegral a n) => a -> Maybe (Finite a n)
+ Data.Finite.Integral: packFiniteProxy :: forall n a proxy. (SaneIntegral a, KnownIntegral a n) => proxy n -> a -> Maybe (Finite a n)
+ Data.Finite.Integral: separateExponential :: forall n m a. (SaneIntegral a, KnownIntegral a m) => Finite a (m ^ n) -> Finite a n -> Finite a m
+ Data.Finite.Integral: separateOne :: forall a. Finite a 1 -> ()
+ Data.Finite.Integral: separateProduct :: forall n m a. (SaneIntegral a, KnownIntegral a n) => Finite a (n * m) -> (Finite a n, Finite a m)
+ Data.Finite.Integral: separateSum :: forall n m a. (SaneIntegral a, KnownIntegral a n) => Finite a (n + m) -> Either (Finite a n) (Finite a m)
+ Data.Finite.Integral: separateZero :: forall a. SaneIntegral a => Finite a 0 -> Void
+ Data.Finite.Integral: shift :: forall n a. (SaneIntegral a, Limited a (n + 1)) => Finite a n -> Finite a (n + 1)
+ Data.Finite.Integral: shiftN :: forall n m a. (SaneIntegral a, KnownIntegral a n, KnownIntegral a m, n <= m) => Finite a n -> Finite a m
+ Data.Finite.Integral: shiftProxy :: forall n k a proxy. (SaneIntegral a, KnownIntegral a k, Limited a (n + k)) => proxy k -> Finite a n -> Finite a (n + k)
+ Data.Finite.Integral: strengthen :: forall n a. (SaneIntegral a, KnownIntegral a n) => Finite a (n + 1) -> Maybe (Finite a n)
+ Data.Finite.Integral: strengthenN :: forall n m a. (SaneIntegral a, KnownIntegral a m, Limited a m) => Finite a n -> Maybe (Finite a m)
+ Data.Finite.Integral: strengthenProxy :: forall n k a proxy. (SaneIntegral a, KnownIntegral a n) => proxy k -> Finite a (n + k) -> Maybe (Finite a n)
+ Data.Finite.Integral: sub :: forall n m a. SaneIntegral a => Finite a n -> Finite a m -> Either (Finite a m) (Finite a n)
+ Data.Finite.Integral: type Limited a (n :: Nat) = LeqMaybe n (Limit a)
+ Data.Finite.Integral: unshift :: forall n a. SaneIntegral a => Finite a (n + 1) -> Maybe (Finite a n)
+ Data.Finite.Integral: unshiftN :: forall n m a. (SaneIntegral a, KnownIntegral a n, KnownIntegral a m, Limited a m) => Finite a n -> Maybe (Finite a m)
+ Data.Finite.Integral: unshiftProxy :: forall n k a proxy. (SaneIntegral a, KnownIntegral a k) => proxy k -> Finite a (n + k) -> Maybe (Finite a n)
+ Data.Finite.Integral: weaken :: forall n a. Limited a (n + 1) => Finite a n -> Finite a (n + 1)
+ Data.Finite.Integral: weakenN :: forall n m a. (n <= m, Limited a m) => Finite a n -> Finite a m
+ Data.Finite.Integral: weakenProxy :: forall n k a proxy. Limited a (n + k) => proxy k -> Finite a n -> Finite a (n + k)
+ Data.Finite.Integral: withIntegral :: forall a n r proxy1 proxy2. (SaneIntegral a, KnownIntegral a n) => proxy1 a -> proxy2 n -> (KnownNat n => r) -> r
+ Data.Finite.Internal: pattern Finite :: forall n. Integer -> Finite n
+ Data.Finite.Internal: type Finite = Finite Integer
+ Data.Finite.Internal.Integral: Finite :: a -> Finite a (n :: Nat)
+ Data.Finite.Internal.Integral: class KnownIntegral a (n :: Nat)
+ Data.Finite.Internal.Integral: class Integral a => SaneIntegral a where {
+ Data.Finite.Internal.Integral: finite :: forall n a. (SaneIntegral a, KnownIntegral a n) => a -> Finite a n
+ Data.Finite.Internal.Integral: getFinite :: forall n a. Finite a n -> a
+ Data.Finite.Internal.Integral: instance (Data.Finite.Internal.Integral.SaneIntegral a, Data.Finite.Internal.Integral.KnownIntegral a n) => GHC.Enum.Bounded (Data.Finite.Internal.Integral.Finite a n)
+ Data.Finite.Internal.Integral: instance (Data.Finite.Internal.Integral.SaneIntegral a, Data.Finite.Internal.Integral.KnownIntegral a n) => GHC.Enum.Enum (Data.Finite.Internal.Integral.Finite a n)
+ Data.Finite.Internal.Integral: instance (Data.Finite.Internal.Integral.SaneIntegral a, Data.Finite.Internal.Integral.KnownIntegral a n) => GHC.Num.Num (Data.Finite.Internal.Integral.Finite a n)
+ Data.Finite.Internal.Integral: instance (Data.Finite.Internal.Integral.SaneIntegral a, Data.Finite.Internal.Integral.KnownIntegral a n) => GHC.Real.Integral (Data.Finite.Internal.Integral.Finite a n)
+ Data.Finite.Internal.Integral: instance (Data.Finite.Internal.Integral.SaneIntegral a, Data.Finite.Internal.Integral.KnownIntegral a n) => GHC.Real.Real (Data.Finite.Internal.Integral.Finite a n)
+ Data.Finite.Internal.Integral: instance (Data.Finite.Internal.Integral.SaneIntegral a, Data.Finite.Internal.Integral.Limited a n, GHC.TypeNats.KnownNat n) => Data.Finite.Internal.Integral.KnownIntegral a n
+ Data.Finite.Internal.Integral: instance (GHC.Read.Read a, Data.Finite.Internal.Integral.SaneIntegral a, Data.Finite.Internal.Integral.KnownIntegral a n) => GHC.Read.Read (Data.Finite.Internal.Integral.Finite a n)
+ Data.Finite.Internal.Integral: instance (n Data.Type.Ord.<= m) => Data.Finite.Internal.Integral.LeqMaybe n ('GHC.Maybe.Just m)
+ Data.Finite.Internal.Integral: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Data.Finite.Internal.Integral.Finite a n)
+ Data.Finite.Internal.Integral: instance Data.Finite.Internal.Integral.LeqMaybe n 'GHC.Maybe.Nothing
+ Data.Finite.Internal.Integral: instance Data.Finite.Internal.Integral.SaneIntegral GHC.Int.Int16
+ Data.Finite.Internal.Integral: instance Data.Finite.Internal.Integral.SaneIntegral GHC.Int.Int32
+ Data.Finite.Internal.Integral: instance Data.Finite.Internal.Integral.SaneIntegral GHC.Int.Int64
+ Data.Finite.Internal.Integral: instance Data.Finite.Internal.Integral.SaneIntegral GHC.Int.Int8
+ Data.Finite.Internal.Integral: instance Data.Finite.Internal.Integral.SaneIntegral GHC.Num.Integer.Integer
+ Data.Finite.Internal.Integral: instance Data.Finite.Internal.Integral.SaneIntegral GHC.Num.Natural.Natural
+ Data.Finite.Internal.Integral: instance Data.Finite.Internal.Integral.SaneIntegral GHC.Types.Int
+ Data.Finite.Internal.Integral: instance Data.Finite.Internal.Integral.SaneIntegral GHC.Types.Word
+ Data.Finite.Internal.Integral: instance Data.Finite.Internal.Integral.SaneIntegral GHC.Word.Word16
+ Data.Finite.Internal.Integral: instance Data.Finite.Internal.Integral.SaneIntegral GHC.Word.Word32
+ Data.Finite.Internal.Integral: instance Data.Finite.Internal.Integral.SaneIntegral GHC.Word.Word64
+ Data.Finite.Internal.Integral: instance Data.Finite.Internal.Integral.SaneIntegral GHC.Word.Word8
+ Data.Finite.Internal.Integral: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.Finite.Internal.Integral.Finite a n)
+ Data.Finite.Internal.Integral: instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.Finite.Internal.Integral.Finite a n)
+ Data.Finite.Internal.Integral: instance GHC.Ix.Ix a => GHC.Ix.Ix (Data.Finite.Internal.Integral.Finite a n)
+ Data.Finite.Internal.Integral: instance GHC.Show.Show a => GHC.Show.Show (Data.Finite.Internal.Integral.Finite a n)
+ Data.Finite.Internal.Integral: intVal :: forall n a proxy. KnownIntegral a n => proxy n -> a
+ Data.Finite.Internal.Integral: modAdd :: SaneIntegral a => a -> a -> a -> a
+ Data.Finite.Internal.Integral: modMul :: SaneIntegral a => a -> a -> a -> a
+ Data.Finite.Internal.Integral: modSub :: SaneIntegral a => a -> a -> a -> a
+ Data.Finite.Internal.Integral: newtype Finite a (n :: Nat)
+ Data.Finite.Internal.Integral: type Limit a :: Maybe Nat;
+ Data.Finite.Internal.Integral: type Limited a (n :: Nat) = LeqMaybe n (Limit a)
+ Data.Finite.Internal.Integral: withIntegral :: forall a n r proxy1 proxy2. (SaneIntegral a, KnownIntegral a n) => proxy1 a -> proxy2 n -> (KnownNat n => r) -> r
+ Data.Finite.Internal.Integral: withLimited :: forall a n r lim proxy1 proxy2. (Limit a ~ 'Just lim, KnownIntegral a n) => proxy1 a -> proxy2 n -> (Limited a n => r) -> r
+ Data.Finite.Internal.Integral: }
- Data.Finite: add :: Finite n -> Finite m -> Finite (n + m)
+ Data.Finite: add :: forall n m. Finite n -> Finite m -> Finite (n + m)
- Data.Finite: cmp :: Finite n -> Finite m -> Ordering
+ Data.Finite: cmp :: forall n m. Finite n -> Finite m -> Ordering
- Data.Finite: combineProduct :: KnownNat n => (Finite n, Finite m) -> Finite (n * m)
+ Data.Finite: combineProduct :: forall n m. KnownNat n => (Finite n, Finite m) -> Finite (n * m)
- Data.Finite: combineSum :: KnownNat n => Either (Finite n) (Finite m) -> Finite (n + m)
+ Data.Finite: combineSum :: forall n m. KnownNat n => Either (Finite n) (Finite m) -> Finite (n + m)
- Data.Finite: equals :: Finite n -> Finite m -> Bool
+ Data.Finite: equals :: forall n m. Finite n -> Finite m -> Bool
- Data.Finite: finite :: KnownNat n => Integer -> Finite n
+ Data.Finite: finite :: forall n. KnownNat n => Integer -> Finite n
- Data.Finite: finiteProxy :: KnownNat n => proxy n -> Integer -> Finite n
+ Data.Finite: finiteProxy :: forall n proxy. KnownNat n => proxy n -> Integer -> Finite n
- Data.Finite: finites :: KnownNat n => [Finite n]
+ Data.Finite: finites :: forall n. KnownNat n => [Finite n]
- Data.Finite: finitesProxy :: KnownNat n => proxy n -> [Finite n]
+ Data.Finite: finitesProxy :: forall n proxy. KnownNat n => proxy n -> [Finite n]
- Data.Finite: getFinite :: Finite n -> Integer
+ Data.Finite: getFinite :: forall n. Finite n -> Integer
- Data.Finite: isValidFinite :: KnownNat n => Finite n -> Bool
+ Data.Finite: isValidFinite :: forall n. KnownNat n => Finite n -> Bool
- Data.Finite: modulo :: KnownNat n => Integer -> Finite n
+ Data.Finite: modulo :: forall n. KnownNat n => Integer -> Finite n
- Data.Finite: moduloProxy :: KnownNat n => proxy n -> Integer -> Finite n
+ Data.Finite: moduloProxy :: forall n proxy. KnownNat n => proxy n -> Integer -> Finite n
- Data.Finite: multiply :: Finite n -> Finite m -> Finite (n * m)
+ Data.Finite: multiply :: forall n m. Finite n -> Finite m -> Finite (n * m)
- Data.Finite: natToFinite :: (KnownNat n, KnownNat m, (n + 1) <= m) => proxy n -> Finite m
+ Data.Finite: natToFinite :: forall n m proxy. (KnownNat n, KnownNat m, (n + 1) <= m) => proxy n -> Finite m
- Data.Finite: packFinite :: KnownNat n => Integer -> Maybe (Finite n)
+ Data.Finite: packFinite :: forall n. KnownNat n => Integer -> Maybe (Finite n)
- Data.Finite: packFiniteProxy :: KnownNat n => proxy n -> Integer -> Maybe (Finite n)
+ Data.Finite: packFiniteProxy :: forall n proxy. KnownNat n => proxy n -> Integer -> Maybe (Finite n)
- Data.Finite: separateProduct :: KnownNat n => Finite (n * m) -> (Finite n, Finite m)
+ Data.Finite: separateProduct :: forall n m. KnownNat n => Finite (n * m) -> (Finite n, Finite m)
- Data.Finite: separateSum :: KnownNat n => Finite (n + m) -> Either (Finite n) (Finite m)
+ Data.Finite: separateSum :: forall n m. KnownNat n => Finite (n + m) -> Either (Finite n) (Finite m)
- Data.Finite: shift :: Finite n -> Finite (n + 1)
+ Data.Finite: shift :: forall n. Finite n -> Finite (n + 1)
- Data.Finite: shiftN :: (KnownNat n, KnownNat m, n <= m) => Finite n -> Finite m
+ Data.Finite: shiftN :: forall n m. (KnownNat n, KnownNat m, n <= m) => Finite n -> Finite m
- Data.Finite: shiftProxy :: KnownNat k => proxy k -> Finite n -> Finite (n + k)
+ Data.Finite: shiftProxy :: forall n k proxy. KnownNat k => proxy k -> Finite n -> Finite (n + k)
- Data.Finite: strengthen :: KnownNat n => Finite (n + 1) -> Maybe (Finite n)
+ Data.Finite: strengthen :: forall n. KnownNat n => Finite (n + 1) -> Maybe (Finite n)
- Data.Finite: strengthenN :: KnownNat n => Finite m -> Maybe (Finite n)
+ Data.Finite: strengthenN :: forall n m. KnownNat m => Finite n -> Maybe (Finite m)
- Data.Finite: strengthenProxy :: KnownNat n => proxy k -> Finite (n + k) -> Maybe (Finite n)
+ Data.Finite: strengthenProxy :: forall n k proxy. KnownNat n => proxy k -> Finite (n + k) -> Maybe (Finite n)
- Data.Finite: sub :: Finite n -> Finite m -> Either (Finite m) (Finite n)
+ Data.Finite: sub :: forall n m. Finite n -> Finite m -> Either (Finite m) (Finite n)
- Data.Finite: unshift :: Finite (n + 1) -> Maybe (Finite n)
+ Data.Finite: unshift :: forall n. Finite (n + 1) -> Maybe (Finite n)
- Data.Finite: unshiftN :: (KnownNat n, KnownNat m) => Finite m -> Maybe (Finite n)
+ Data.Finite: unshiftN :: forall n m. (KnownNat n, KnownNat m) => Finite n -> Maybe (Finite m)
- Data.Finite: unshiftProxy :: KnownNat k => proxy k -> Finite (n + k) -> Maybe (Finite n)
+ Data.Finite: unshiftProxy :: forall n k proxy. KnownNat k => proxy k -> Finite (n + k) -> Maybe (Finite n)
- Data.Finite: weaken :: Finite n -> Finite (n + 1)
+ Data.Finite: weaken :: forall n. Finite n -> Finite (n + 1)
- Data.Finite: weakenN :: n <= m => Finite n -> Finite m
+ Data.Finite: weakenN :: forall n m. n <= m => Finite n -> Finite m
- Data.Finite: weakenProxy :: proxy k -> Finite n -> Finite (n + k)
+ Data.Finite: weakenProxy :: forall n k proxy. proxy k -> Finite n -> Finite (n + k)
- Data.Finite.Internal: finite :: KnownNat n => Integer -> Finite n
+ Data.Finite.Internal: finite :: forall n. KnownNat n => Integer -> Finite n
- Data.Finite.Internal: getFinite :: Finite n -> Integer
+ Data.Finite.Internal: getFinite :: forall n. Finite n -> Integer
Files
- finite-typelits.cabal +11/−7
- src/Data/Finite.hs +119/−107
- src/Data/Finite/Integral.hs +353/−0
- src/Data/Finite/Internal.hs +21/−90
- src/Data/Finite/Internal/Integral.hs +460/−0
- test/Main.hs +1115/−539
finite-typelits.cabal view
@@ -1,5 +1,5 @@ name: finite-typelits-version: 0.1.6.0+version: 0.2.0.0 synopsis: A type inhabited by finitely many values, indexed by type-level naturals description: A type inhabited by finitely many values, indexed by type-level naturals. homepage: https://github.com/mniip/finite-typelits@@ -13,18 +13,22 @@ library exposed-modules: Data.Finite+ , Data.Finite.Integral , Data.Finite.Internal- build-depends: base >= 4.7 && < 4.18- , deepseq >= 1.4+ , Data.Finite.Internal.Integral+ build-depends: base >= 4.7 && < 4.20+ , deepseq >= 1.3 && < 1.6+ , tagged >= 0.8 && < 0.9+ , template-haskell >= 2.9 && < 2.22 hs-source-dirs: src default-language: Haskell2010 ghc-options: -Wall -test-Suite finite-typelits-tests+test-suite finite-typelits-tests type: exitcode-stdio-1.0 main-is: test/Main.hs build-depends: finite-typelits- , base >= 4.9 && < 4.18- , deepseq >= 1.4- , QuickCheck+ , base >= 4.9 && < 4.20+ , deepseq >= 1.3 && < 1.6+ , QuickCheck >= 2.12 && < 2.15 default-language: Haskell2010
src/Data/Finite.hs view
@@ -8,7 +8,9 @@ -- Portability : portable -------------------------------------------------------------------------------- {-# LANGUAGE DataKinds #-}+{-# LANGUAGE ExplicitForAll #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} module Data.Finite@@ -24,185 +26,195 @@ weakenN, strengthenN, shiftN, unshiftN, weakenProxy, strengthenProxy, shiftProxy, unshiftProxy, add, sub, multiply,- combineSum, combineProduct,- separateSum, separateProduct,+ combineSum, combineZero, combineProduct, combineOne, combineExponential,+ separateSum, separateZero, separateProduct, separateOne,+ separateExponential, isValidFinite ) where -import Data.Maybe import GHC.TypeLits+import Data.Void +import qualified Data.Finite.Integral as I import Data.Finite.Internal -- | Convert an 'Integer' into a 'Finite', returning 'Nothing' if the input is -- out of bounds.-packFinite :: KnownNat n => Integer -> Maybe (Finite n)-packFinite x = result- where- result = if x < natVal (fromJust result) && x >= 0- then Just $ Finite x- else Nothing+packFinite :: forall n. KnownNat n => Integer -> Maybe (Finite n)+packFinite = I.packFinite -- | Same as 'packFinite' but with a proxy argument to avoid type signatures.-packFiniteProxy :: KnownNat n => proxy n -> Integer -> Maybe (Finite n)-packFiniteProxy _ = packFinite+packFiniteProxy+ :: forall n proxy. KnownNat n+ => proxy n -> Integer -> Maybe (Finite n)+packFiniteProxy = I.packFiniteProxy -- | Same as 'finite' but with a proxy argument to avoid type signatures.-finiteProxy :: KnownNat n => proxy n -> Integer -> Finite n-finiteProxy _ = finite+finiteProxy :: forall n proxy. KnownNat n => proxy n -> Integer -> Finite n+finiteProxy = I.finiteProxy -- | Generate a list of length @n@ of all elements of @'Finite' n@.-finites :: KnownNat n => [Finite n]-finites = results- where- results = Finite `fmap` [0 .. (natVal (head results) - 1)]+finites :: forall n. KnownNat n => [Finite n]+finites = I.finites -- | Same as 'finites' but with a proxy argument to avoid type signatures.-finitesProxy :: KnownNat n => proxy n -> [Finite n]-finitesProxy _ = finites+finitesProxy :: forall n proxy. KnownNat n => proxy n -> [Finite n]+finitesProxy = I.finitesProxy -- | Produce the 'Finite' that is congruent to the given integer modulo @n@.-modulo :: KnownNat n => Integer -> Finite n-modulo x = result- where- result = if natVal result == 0- then error "modulo: division by zero"- else Finite (x `mod` natVal result)+modulo :: forall n. KnownNat n => Integer -> Finite n+modulo = I.modulo -- | Same as 'modulo' but with a proxy argument to avoid type signatures.-moduloProxy :: KnownNat n => proxy n -> Integer -> Finite n-moduloProxy _ = modulo+moduloProxy :: forall n proxy. KnownNat n => proxy n -> Integer -> Finite n+moduloProxy = I.moduloProxy -- | Test two different types of finite numbers for equality.-equals :: Finite n -> Finite m -> Bool-equals (Finite x) (Finite y) = x == y+equals :: forall n m. Finite n -> Finite m -> Bool+equals = I.equals infix 4 `equals` -- | Compare two different types of finite numbers.-cmp :: Finite n -> Finite m -> Ordering-cmp (Finite x) (Finite y) = x `compare` y+cmp :: forall n m. Finite n -> Finite m -> Ordering+cmp = I.cmp -- | Convert a type-level literal into a 'Finite'.-natToFinite :: (KnownNat n, KnownNat m, n + 1 <= m) => proxy n -> Finite m-natToFinite p = Finite $ natVal p+natToFinite+ :: forall n m proxy. (KnownNat n, KnownNat m, n + 1 <= m)+ => proxy n -> Finite m+natToFinite = I.natToFinite -- | Add one inhabitant in the end.-weaken :: Finite n -> Finite (n + 1)-weaken (Finite x) = Finite x+weaken :: forall n. Finite n -> Finite (n + 1)+weaken = I.weaken -- | Remove one inhabitant from the end. Returns 'Nothing' if the input was the -- removed inhabitant.-strengthen :: KnownNat n => Finite (n + 1) -> Maybe (Finite n)-strengthen (Finite x) = result- where- result = if x < natVal (fromJust result)- then Just $ Finite x- else Nothing+strengthen :: forall n. KnownNat n => Finite (n + 1) -> Maybe (Finite n)+strengthen = I.strengthen -- | Add one inhabitant in the beginning, shifting everything up by one.-shift :: Finite n -> Finite (n + 1)-shift (Finite x) = Finite (x + 1)+shift :: forall n. Finite n -> Finite (n + 1)+shift = I.shift -- | Remove one inhabitant from the beginning, shifting everything down by one. -- Returns 'Nothing' if the input was the removed inhabitant.-unshift :: Finite (n + 1) -> Maybe (Finite n)-unshift (Finite x) = if x < 1- then Nothing- else Just $ Finite $ x - 1+unshift :: forall n. Finite (n + 1) -> Maybe (Finite n)+unshift = I.unshift -- | Add multiple inhabitants in the end.-weakenN :: (n <= m) => Finite n -> Finite m-weakenN (Finite x) = Finite x+weakenN :: forall n m. (n <= m) => Finite n -> Finite m+weakenN = I.weakenN -- | Remove multiple inhabitants from the end. Returns 'Nothing' if the input -- was one of the removed inhabitants.-strengthenN :: KnownNat n => Finite m -> Maybe (Finite n)-strengthenN (Finite x) = result- where- result = if x < natVal (fromJust result)- then Just $ Finite x- else Nothing+strengthenN :: forall n m. KnownNat m => Finite n -> Maybe (Finite m)+strengthenN = I.strengthenN -- | Add multiple inhabitants in the beginning, shifting everything up by the -- amount of inhabitants added.-shiftN :: (KnownNat n, KnownNat m, n <= m) => Finite n -> Finite m-shiftN fx@(Finite x) = result- where- result = Finite $ x + natVal result - natVal fx+shiftN :: forall n m. (KnownNat n, KnownNat m, n <= m) => Finite n -> Finite m+shiftN = I.shiftN -- | Remove multiple inhabitants from the beginning, shifting everything down by -- the amount of inhabitants removed. Returns 'Nothing' if the input was one of -- the removed inhabitants.-unshiftN :: (KnownNat n, KnownNat m) => Finite m -> Maybe (Finite n)-unshiftN fx@(Finite x) = result- where- result = if x < natVal fx - natVal (fromJust result)- then Nothing- else Just $ Finite $ x - natVal fx + natVal (fromJust result)+unshiftN :: forall n m. (KnownNat n, KnownNat m) => Finite n -> Maybe (Finite m)+unshiftN = I.unshiftN -weakenProxy :: proxy k -> Finite n -> Finite (n + k)-weakenProxy _ (Finite x) = Finite x+weakenProxy :: forall n k proxy. proxy k -> Finite n -> Finite (n + k)+weakenProxy = I.weakenProxy -strengthenProxy :: KnownNat n => proxy k -> Finite (n + k) -> Maybe (Finite n)-strengthenProxy _ (Finite x) = result- where- result = if x < natVal (fromJust result)- then Just $ Finite x- else Nothing+strengthenProxy+ :: forall n k proxy. KnownNat n+ => proxy k -> Finite (n + k) -> Maybe (Finite n)+strengthenProxy = I.strengthenProxy -shiftProxy :: KnownNat k => proxy k -> Finite n -> Finite (n + k)-shiftProxy p (Finite x) = Finite $ x + natVal p+shiftProxy+ :: forall n k proxy. KnownNat k+ => proxy k -> Finite n -> Finite (n + k)+shiftProxy = I.shiftProxy -unshiftProxy :: KnownNat k => proxy k -> Finite (n + k) -> Maybe (Finite n)-unshiftProxy p (Finite x) = if x < natVal p- then Nothing- else Just $ Finite $ x - natVal p+unshiftProxy+ :: forall n k proxy. KnownNat k+ => proxy k -> Finite (n + k) -> Maybe (Finite n)+unshiftProxy = I.unshiftProxy -- | Add two 'Finite's.-add :: Finite n -> Finite m -> Finite (n + m)-add (Finite x) (Finite y) = Finite $ x + y+add :: forall n m. Finite n -> Finite m -> Finite (n + m)+add = I.add -- | Subtract two 'Finite's. Returns 'Left' for negative results, and 'Right' -- for positive results. Note that this function never returns @'Left' 0@.-sub :: Finite n -> Finite m -> Either (Finite m) (Finite n)-sub (Finite x) (Finite y) = if x >= y- then Right $ Finite $ x - y- else Left $ Finite $ y - x+sub :: forall n m. Finite n -> Finite m -> Either (Finite m) (Finite n)+sub = I.sub -- | Multiply two 'Finite's.-multiply :: Finite n -> Finite m -> Finite (n GHC.TypeLits.* m)-multiply (Finite x) (Finite y) = Finite $ x * y--getLeftType :: Either a b -> a-getLeftType = error "getLeftType"+multiply :: forall n m. Finite n -> Finite m -> Finite (n GHC.TypeLits.* m)+multiply = I.multiply -- | 'Left'-biased (left values come first) disjoint union of finite sets.-combineSum :: KnownNat n => Either (Finite n) (Finite m) -> Finite (n + m)-combineSum (Left (Finite x)) = Finite x-combineSum efx@(Right (Finite x)) = Finite $ x + natVal (getLeftType efx)+combineSum+ :: forall n m. KnownNat n+ => Either (Finite n) (Finite m) -> Finite (n + m)+combineSum = I.combineSum +-- | Witness that 'combineSum' preserves units: @0@ is the unit of+-- 'GHC.TypeLits.+', and 'Void' is the unit of 'Either'.+combineZero :: Void -> Finite 0+combineZero = I.combineZero+ -- | 'fst'-biased (fst is the inner, and snd is the outer iteratee) product of -- finite sets.-combineProduct :: KnownNat n => (Finite n, Finite m) -> Finite (n GHC.TypeLits.* m)-combineProduct (fx@(Finite x), Finite y) = Finite $ x + y * natVal fx+combineProduct+ :: forall n m. KnownNat n+ => (Finite n, Finite m) -> Finite (n GHC.TypeLits.* m)+combineProduct = I.combineProduct +-- | Witness that 'combineProduct' preserves units: @1@ is the unit of+-- 'GHC.TypeLits.*', and '()' is the unit of '(,)'.+combineOne :: () -> Finite 1+combineOne = I.combineOne++-- | Product of @n@ copies of a finite set of size @m@, biased towards the lower+-- values of the argument (colex order).+combineExponential+ :: forall n m. (KnownNat m, KnownNat n)+ => (Finite n -> Finite m) -> Finite (m ^ n)+combineExponential = I.combineExponential+ -- | Take a 'Left'-biased disjoint union apart.-separateSum :: KnownNat n => Finite (n + m) -> Either (Finite n) (Finite m)-separateSum (Finite x) = result- where- result = if x >= natVal (getLeftType result)- then Right $ Finite $ x - natVal (getLeftType result)- else Left $ Finite x+separateSum+ :: forall n m. KnownNat n+ => Finite (n + m) -> Either (Finite n) (Finite m)+separateSum = I.separateSum +-- | Witness that 'separateSum' preserves units: @0@ is the unit of+-- 'GHC.TypeLits.+', and 'Void' is the unit of 'Either'.+--+-- Also witness that a @'Finite' 0@ is uninhabited.+separateZero :: Finite 0 -> Void+separateZero = I.separateZero+ -- | Take a 'fst'-biased product apart.-separateProduct :: KnownNat n => Finite (n GHC.TypeLits.* m) -> (Finite n, Finite m)-separateProduct (Finite x) = result- where- result = (Finite $ x `mod` natVal (fst result), Finite $ x `div` natVal (fst result))+separateProduct+ :: forall n m. KnownNat n+ => Finite (n GHC.TypeLits.* m) -> (Finite n, Finite m)+separateProduct = I.separateProduct +separateOne :: Finite 1 -> ()+separateOne = I.separateOne++-- | Take a product of @n@ copies of a finite set of size @m@ apart, biased+-- towards the lower values of the argument (colex order).+separateExponential+ :: forall n m. KnownNat m+ => Finite (m ^ n) -> Finite n -> Finite m+separateExponential = I.separateExponential+ -- | Verifies that a given 'Finite' is valid. Should always return 'True' unless -- you bring the @Data.Finite.Internal.Finite@ constructor into the scope, or -- use 'Unsafe.Coerce.unsafeCoerce' or other nasty hacks.-isValidFinite :: KnownNat n => Finite n -> Bool-isValidFinite fx@(Finite x) = x < natVal fx && x >= 0+isValidFinite :: forall n. KnownNat n => Finite n -> Bool+isValidFinite = I.isValidFinite
+ src/Data/Finite/Integral.hs view
@@ -0,0 +1,353 @@+--------------------------------------------------------------------------------+-- |+-- Module : Data.Finite.Integral+-- Copyright : (C) 2015-2022 mniip+-- License : BSD3+-- Maintainer : mniip <mniip@mniip.com>+-- Stability : experimental+-- Portability : portable+--------------------------------------------------------------------------------+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE ExplicitForAll #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+module Data.Finite.Integral+ (+ SaneIntegral, Limited, KnownIntegral, intVal,+ withIntegral,+ Finite,+ packFinite, packFiniteProxy,+ finite, finiteProxy,+ getFinite, finites, finitesProxy,+ modulo, moduloProxy,+ equals, cmp,+ natToFinite,+ weaken, strengthen, shift, unshift,+ weakenN, strengthenN, shiftN, unshiftN,+ weakenProxy, strengthenProxy, shiftProxy, unshiftProxy,+ add, sub, multiply,+ combineSum, combineZero, combineProduct, combineOne, combineExponential,+ separateSum, separateZero, separateProduct, separateOne,+ separateExponential,+ isValidFinite+ )+ where++import Data.Coerce+import Data.List+import Data.Proxy+import Data.Void+import GHC.TypeLits++import Data.Finite.Internal.Integral++-- | Convert an @a@ into a @'Finite' a@, returning 'Nothing' if the input is+-- out of bounds.+packFinite+ :: forall n a. (SaneIntegral a, KnownIntegral a n)+ => a -> Maybe (Finite a n)+packFinite x+ | x < n && x >= 0 = Just $ Finite x+ | otherwise = Nothing+ where n = intVal (Proxy :: Proxy n)+{-# INLINABLE packFinite #-}++-- | Same as 'packFinite' but with a proxy argument to avoid type signatures.+packFiniteProxy+ :: forall n a proxy. (SaneIntegral a, KnownIntegral a n)+ => proxy n -> a -> Maybe (Finite a n)+packFiniteProxy _ = packFinite+{-# INLINABLE packFiniteProxy #-}++-- | Same as 'finite' but with a proxy argument to avoid type signatures.+finiteProxy+ :: forall n a proxy. (SaneIntegral a, KnownIntegral a n)+ => proxy n -> a -> Finite a n+finiteProxy _ = finite+{-# INLINABLE finiteProxy #-}++-- | Generate an ascending list of length @n@ of all elements of @'Finite' a n@.+finites :: forall n a. (SaneIntegral a, KnownIntegral a n) => [Finite a n]+finites = Finite `fmap` takeWhile (< n) [0..]+ -- [0 .. n - 1] does not work if n is 0 of an unsigned type+ where n = intVal (Proxy :: Proxy n)+{-# INLINABLE finites #-}++-- | Same as 'finites' but with a proxy argument to avoid type signatures.+finitesProxy+ :: forall n a proxy. (SaneIntegral a, KnownIntegral a n)+ => proxy n -> [Finite a n]+finitesProxy _ = finites+{-# INLINABLE finitesProxy #-}++-- | Produce the 'Finite' that is congruent to the given integer modulo @n@.+modulo :: forall n a. (SaneIntegral a, KnownIntegral a n) => a -> Finite a n+modulo x+ | n == 0 = error "modulo: division by zero"+ | otherwise = Finite $ x `mod` n+ where n = intVal (Proxy :: Proxy n)+{-# INLINABLE modulo #-}++-- | Same as 'modulo' but with a proxy argument to avoid type signatures.+moduloProxy+ :: forall n a proxy. (SaneIntegral a, KnownIntegral a n)+ => proxy n -> a -> Finite a n+moduloProxy _ = modulo+{-# INLINABLE moduloProxy #-}++-- | Test two different types of finite numbers for equality.+equals :: forall n m a. Eq a => Finite a n -> Finite a m -> Bool+equals = coerce ((==) :: a -> a -> Bool)+infix 4 `equals`+{-# INLINABLE equals #-}++-- | Compare two different types of finite numbers.+cmp :: forall n m a. Ord a => Finite a n -> Finite a m -> Ordering+cmp = coerce (compare :: a -> a -> Ordering)+{-# INLINABLE cmp #-}++-- | Convert a type-level literal into a 'Finite'.+natToFinite+ :: forall n m a proxy.+ (SaneIntegral a, KnownIntegral a n, Limited a m, n + 1 <= m)+ => proxy n -> Finite a m+natToFinite p = Finite $ intVal p+{-# INLINABLE natToFinite #-}++-- | Add one inhabitant in the end.+weaken :: forall n a. Limited a (n + 1) => Finite a n -> Finite a (n + 1)+weaken = coerce+{-# INLINABLE weaken #-}++-- | Remove one inhabitant from the end. Returns 'Nothing' if the input was the+-- removed inhabitant.+strengthen+ :: forall n a. (SaneIntegral a, KnownIntegral a n)+ => Finite a (n + 1) -> Maybe (Finite a n)+strengthen (Finite x)+ | x < n = Just $ Finite x+ | otherwise = Nothing+ where n = intVal (Proxy :: Proxy n)+{-# INLINABLE strengthen #-}++-- | Add one inhabitant in the beginning, shifting everything up by one.+shift+ :: forall n a. (SaneIntegral a, Limited a (n + 1))+ => Finite a n -> Finite a (n + 1)+shift (Finite x) = Finite $ x + 1+{-# INLINABLE shift #-}++-- | Remove one inhabitant from the beginning, shifting everything down by one.+-- Returns 'Nothing' if the input was the removed inhabitant.+unshift :: forall n a. SaneIntegral a => Finite a (n + 1) -> Maybe (Finite a n)+unshift (Finite x)+ | x < 1 = Nothing+ | otherwise = Just $ Finite $ x - 1+{-# INLINABLE unshift #-}++-- | Add multiple inhabitants in the end.+weakenN :: forall n m a. (n <= m, Limited a m) => Finite a n -> Finite a m+weakenN = coerce+{-# INLINABLE weakenN #-}++-- | Remove multiple inhabitants from the end. Returns 'Nothing' if the input+-- was one of the removed inhabitants.+strengthenN+ :: forall n m a. (SaneIntegral a, KnownIntegral a m, Limited a m)+ => Finite a n -> Maybe (Finite a m)+strengthenN (Finite x)+ | x < m = Just $ Finite x+ | otherwise = Nothing+ where m = intVal (Proxy :: Proxy m)+{-# INLINABLE strengthenN #-}++-- | Add multiple inhabitants in the beginning, shifting everything up by the+-- amount of inhabitants added.+shiftN+ :: forall n m a.+ ( SaneIntegral a+ , KnownIntegral a n+ , KnownIntegral a m+ , n <= m+ )+ => Finite a n -> Finite a m+shiftN (Finite x) = Finite $ x + (m - n)+ where+ n = intVal (Proxy :: Proxy n)+ m = intVal (Proxy :: Proxy m)+{-# INLINABLE shiftN #-}++-- | Remove multiple inhabitants from the beginning, shifting everything down by+-- the amount of inhabitants removed. Returns 'Nothing' if the input was one of+-- the removed inhabitants.+unshiftN+ :: forall n m a.+ (SaneIntegral a, KnownIntegral a n, KnownIntegral a m, Limited a m)+ => Finite a n -> Maybe (Finite a m)+unshiftN (Finite x)+ | m >= n = Just $ Finite $ x + (m - n)+ | x < n - m = Nothing+ | otherwise = Just $ Finite $ x - (n - m)+ where+ n = intVal (Proxy :: Proxy n)+ m = intVal (Proxy :: Proxy m)+{-# INLINABLE unshiftN #-}++weakenProxy+ :: forall n k a proxy. (Limited a (n + k))+ => proxy k -> Finite a n -> Finite a (n + k)+weakenProxy _ = coerce+{-# INLINABLE weakenProxy #-}++strengthenProxy+ :: forall n k a proxy. (SaneIntegral a, KnownIntegral a n)+ => proxy k -> Finite a (n + k) -> Maybe (Finite a n)+strengthenProxy _ (Finite x)+ | x < n = Just $ Finite x+ | otherwise = Nothing+ where n = intVal (Proxy :: Proxy n)+{-# INLINABLE strengthenProxy #-}++shiftProxy+ :: forall n k a proxy.+ (SaneIntegral a, KnownIntegral a k, Limited a (n + k))+ => proxy k -> Finite a n -> Finite a (n + k)+shiftProxy _ (Finite x) = Finite $ x + k+ where k = intVal (Proxy :: Proxy k)+{-# INLINABLE shiftProxy #-}++unshiftProxy+ :: forall n k a proxy. (SaneIntegral a, KnownIntegral a k)+ => proxy k -> Finite a (n + k) -> Maybe (Finite a n)+unshiftProxy _ (Finite x)+ | x < k = Nothing+ | otherwise = Just $ Finite $ x - k+ where k = intVal (Proxy :: Proxy k)+{-# INLINABLE unshiftProxy #-}++-- | Add two 'Finite's.+add+ :: forall n m a. (SaneIntegral a, Limited a (n + m))+ => Finite a n -> Finite a m -> Finite a (n + m)+add (Finite x) (Finite y) = Finite $ x + y+{-# INLINABLE add #-}++-- | Subtract two 'Finite's. Returns 'Left' for negative results, and 'Right'+-- for positive results. Note that this function never returns @'Left' 0@.+sub+ :: forall n m a. SaneIntegral a+ => Finite a n -> Finite a m -> Either (Finite a m) (Finite a n)+sub (Finite x) (Finite y)+ | x >= y = Right $ Finite $ x - y+ | otherwise = Left $ Finite $ y - x+{-# INLINABLE sub #-}++-- | Multiply two 'Finite's.+multiply+ :: forall n m a. (SaneIntegral a, Limited a (n GHC.TypeLits.* m))+ => Finite a n -> Finite a m -> Finite a (n GHC.TypeLits.* m)+multiply (Finite x) (Finite y) = Finite $ x * y+{-# INLINABLE multiply #-}++-- | 'Left'-biased (left values come first) disjoint union of finite sets.+combineSum+ :: forall n m a. (SaneIntegral a, KnownIntegral a n, Limited a (n + m))+ => Either (Finite a n) (Finite a m) -> Finite a (n + m)+combineSum (Left (Finite x)) = Finite x+combineSum (Right (Finite x)) = Finite $ x + n+ where n = intVal (Proxy :: Proxy n)+{-# INLINABLE combineSum #-}++-- | Witness that 'combineSum' preserves units: @0@ is the unit of+-- 'GHC.TypeLits.+', and 'Void' is the unit of 'Either'.+combineZero :: forall a. Void -> Finite a 0+combineZero = absurd+{-# INLINABLE combineZero #-}++-- | 'fst'-biased (fst is the inner, and snd is the outer iteratee) product of+-- finite sets.+combineProduct+ :: forall n m a.+ (SaneIntegral a, KnownIntegral a n, Limited a (n GHC.TypeLits.* m))+ => (Finite a n, Finite a m) -> Finite a (n GHC.TypeLits.* m)+combineProduct (Finite x, Finite y) = Finite $ x + y * n+ where n = intVal (Proxy :: Proxy n)+{-# INLINABLE combineProduct #-}++-- | Witness that 'combineProduct' preserves units: @1@ is the unit of+-- 'GHC.TypeLits.*', and '()' is the unit of '(,)'.+combineOne :: forall a. (SaneIntegral a, Limited a 1) => () -> Finite a 1+combineOne _ = Finite 0+{-# INLINABLE combineOne #-}++-- | Product of @n@ copies of a finite set of size @m@, biased towards the lower+-- values of the argument (colex order).+combineExponential+ :: forall n m a.+ (SaneIntegral a, KnownIntegral a m, KnownIntegral a n, Limited a (m ^ n))+ => (Finite a n -> Finite a m) -> Finite a (m ^ n)+combineExponential f+ = Finite $ fst $ foldl' next (0, 1) (finites :: [Finite a n])+ where+ next (acc, power) x = acc' `seq` (acc', m * power)+ where acc' = acc + getFinite (f x) * power+ m = intVal (Proxy :: Proxy m)+{-# INLINABLE combineExponential #-}++-- | Take a 'Left'-biased disjoint union apart.+separateSum+ :: forall n m a. (SaneIntegral a, KnownIntegral a n)+ => Finite a (n + m) -> Either (Finite a n) (Finite a m)+separateSum (Finite x)+ | x >= n = Right $ Finite $ x - n+ | otherwise = Left $ Finite x+ where n = intVal (Proxy :: Proxy n)+{-# INLINABLE separateSum #-}++-- | Witness that 'separateSum' preserves units: @0@ is the unit of+-- 'GHC.TypeLits.+', and 'Void' is the unit of 'Either'.+--+-- Also witness that a @'Finite' a 0@ is uninhabited.+separateZero :: forall a. SaneIntegral a => Finite a 0 -> Void+separateZero (Finite n) = n `seq` error+ ("separateZero: got Finite " ++ show (toInteger n))+{-# INLINABLE separateZero #-}++-- | Take a 'fst'-biased product apart.+separateProduct+ :: forall n m a. (SaneIntegral a, KnownIntegral a n)+ => Finite a (n GHC.TypeLits.* m) -> (Finite a n, Finite a m)+separateProduct (Finite x) = case divMod x n of+ (d, m) -> (Finite m, Finite d)+ where n = intVal (Proxy :: Proxy n)+{-# INLINABLE separateProduct #-}++separateOne :: forall a. Finite a 1 -> ()+separateOne _ = ()+{-# INLINABLE separateOne #-}++-- | Take a product of @n@ copies of a finite set of size @m@ apart, biased+-- towards the lower values of the argument (colex order).+separateExponential+ :: forall n m a. (SaneIntegral a, KnownIntegral a m)+ => Finite a (m ^ n) -> Finite a n -> Finite a m+separateExponential = go+ where+ go (Finite n) (Finite 0) = Finite $ n `mod` m+ go (Finite n) (Finite x) = n' `seq` go (Finite n') (Finite $ x - 1)+ where n' = n `div` m+ m = intVal (Proxy :: Proxy m)+{-# INLINABLE separateExponential #-}++-- | Verifies that a given 'Finite' is valid. Should always return 'True' unless+-- you bring the @Data.Finite.Internal.Finite@ constructor into the scope, or+-- use 'Unsafe.Coerce.unsafeCoerce' or other nasty hacks.+isValidFinite+ :: forall n a. (Ord a, Num a, KnownIntegral a n)+ => Finite a n -> Bool+isValidFinite (Finite x) = x < n && x >= 0+ where n = intVal (Proxy :: Proxy n)+{-# INLINABLE isValidFinite #-}
src/Data/Finite/Internal.hs view
@@ -1,112 +1,43 @@ -------------------------------------------------------------------------------- -- |--- Module : Data.Finite.Internal--- Copyright : (C) 2015-2022 mniip+-- Module : Data.Finite+-- Copyright : (C) 2022-2023 mniip -- License : BSD3 -- Maintainer : mniip <mniip@mniip.com> -- Stability : experimental -- Portability : portable ---------------------------------------------------------------------------------{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE CPP #-} module Data.Finite.Internal (- Finite(Finite),- finite,- getFinite+ Finite, pattern Finite,+ finite, getFinite ) where -import Control.DeepSeq-import Control.Monad-import Data.Ratio-import GHC.Generics-import GHC.Read import GHC.TypeLits-import Text.ParserCombinators.ReadPrec-import Text.Read.Lex --- | Finite number type. @'Finite' n@ is inhabited by exactly @n@ values--- the range @[0, n)@ including @0@ but excluding @n@. Invariants:+import qualified Data.Finite.Internal.Integral as I++-- | Finite number type. The type @'Finite' n@ is inhabited by exactly @n@+-- values in the range @[0, n)@ including @0@ but excluding @n@. Invariants: -- -- prop> getFinite x < natVal x -- prop> getFinite x >= 0-newtype Finite (n :: Nat) = Finite Integer- deriving (Eq, Ord, Generic)+type Finite = I.Finite Integer +#if __GLASGOW_HASKELL__ >= 710+pattern Finite :: forall n. Integer -> Finite n+#endif+pattern Finite x = I.Finite (x :: Integer)+ -- | Convert an 'Integer' into a 'Finite', throwing an error if the input is out -- of bounds.-finite :: KnownNat n => Integer -> Finite n-finite x = result- where- result = if x < natVal result && x >= 0- then Finite x- else error $ "finite: Integer " ++ show x ++ " is not representable in Finite " ++ show (natVal result)+finite :: forall n. KnownNat n => Integer -> Finite n+finite = I.finite -- | Convert a 'Finite' into the corresponding 'Integer'.-getFinite :: Finite n -> Integer-getFinite (Finite x) = x---- | Throws an error for @'Finite' 0@-instance KnownNat n => Bounded (Finite n) where- maxBound = result- where- result = if natVal result > 0- then Finite $ natVal result - 1- else error "maxBound: Finite 0 is uninhabited"- minBound = result- where- result = if natVal result > 0- then Finite 0- else error "minBound: Finite 0 is uninhabited"--instance KnownNat n => Enum (Finite n) where- succ fx@(Finite x) = if x == natVal fx - 1- then error "succ: bad argument"- else Finite $ succ x- pred (Finite x) = if x == 0- then error "pred: bad argument"- else Finite $ pred x- fromEnum = fromEnum . getFinite- toEnum = finite . toEnum- enumFrom x = enumFromTo x maxBound- enumFromTo (Finite x) (Finite y) = Finite `fmap` enumFromTo x y- enumFromThen x y = enumFromThenTo x y (if x >= y then minBound else maxBound)- enumFromThenTo (Finite x) (Finite y) (Finite z) = Finite `fmap` enumFromThenTo x y z--instance Show (Finite n) where- showsPrec d (Finite x) = showParen (d > 9) $ showString "finite " . showsPrec 10 x--instance KnownNat n => Read (Finite n) where- readPrec = parens $ Text.ParserCombinators.ReadPrec.prec 10 $ do- expectP (Ident "finite")- x <- readPrec- let result = finite x- guard (x >= 0 && x < natVal result)- return result---- | 'Prelude.+', 'Prelude.-', and 'Prelude.*' implement arithmetic modulo @n@.--- The 'fromInteger' function raises an error for inputs outside of bounds.-instance KnownNat n => Num (Finite n) where- fx@(Finite x) + Finite y = Finite $ (x + y) `mod` natVal fx- fx@(Finite x) - Finite y = Finite $ (x - y) `mod` natVal fx- fx@(Finite x) * Finite y = Finite $ (x * y) `mod` natVal fx- abs fx = fx- signum (Finite x) = fromInteger $ if x == 0 then 0 else 1- fromInteger x = result- where- result = if x < natVal result && x >= 0- then Finite x- else error $ "fromInteger: Integer " ++ show x ++ " is not representable in Finite " ++ show (natVal result)--instance KnownNat n => Real (Finite n) where- toRational (Finite x) = x % 1---- | 'quot' and 'rem' are the same as 'div' and 'mod' and they implement regular--- division of numbers in the range @[0, n)@, __not__ modular arithmetic.-instance KnownNat n => Integral (Finite n) where- quotRem (Finite x) (Finite y) = (Finite $ x `quot` y, Finite $ x `rem` y)- toInteger (Finite x) = x--instance NFData (Finite n)+getFinite :: forall n. Finite n -> Integer+getFinite = I.getFinite
+ src/Data/Finite/Internal/Integral.hs view
@@ -0,0 +1,460 @@+--------------------------------------------------------------------------------+-- |+-- Module : Data.Finite.Internal.Integral+-- Copyright : (C) 2015-2024 mniip+-- License : BSD3+-- Maintainer : mniip <mniip@mniip.com>+-- Stability : experimental+-- Portability : portable+--------------------------------------------------------------------------------+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RoleAnnotations #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UndecidableInstances #-}+#if __GLASGOW_HASKELL__ >= 800+{-# LANGUAGE UndecidableSuperClasses #-}+#endif+module Data.Finite.Internal.Integral+ (+ SaneIntegral(..), Limited, KnownIntegral, intVal,+ withIntegral, withLimited,+ Finite(Finite), finite, getFinite+ )+ where++#if MIN_VERSION_base(4,8,0)+import Numeric.Natural+#endif+import Control.DeepSeq+import Control.Monad+import Data.Ix+import Data.Int+import Data.Proxy+import Data.Tagged+import Data.Type.Equality+import Data.Word+import GHC.Exts+import GHC.Read+import GHC.TypeLits+import Language.Haskell.TH.Lib+import Text.ParserCombinators.ReadPrec+import Text.Read.Lex+import Unsafe.Coerce++#include "MachDeps.h"++-- | A class of datatypes that faithfully represent a sub-range of 'Integer'+-- that includes @0@. A valid instance must obey the following laws:+--+-- 'fromInteger' must be a retract of 'toInteger':+--+-- prop> fromInteger (toInteger a) == a+--+-- Restricted to the range @[0, 'Limit']@ (with 'Nothing' understood as positive+-- infinity), 'fromInteger' must be an inverse of 'toInteger':+--+-- prop> limited i ==> toInteger (fromInteger i) == i+-- where:+--+-- > limited i = case limit of+-- > Just l -> 0 <= i && i <= l+-- > Nothing -> 0 <= i+--+-- __WARNING__: violating the above constraint in particular breaks type safety.+--+-- The implementations of 'Ord', 'Enum', 'Num', 'Integral' must be compatible+-- with that of 'Integer', whenever all arguments and results fall within+-- @[0, 'Limit']@, for example:+--+-- prop> limited i && limited j && limited k && (i * j == k) ==> (fromInteger i * fromInteger j == fromInteger k)+--+-- Methods 'modAdd', 'modSub', and 'modMul' implement modular addition,+-- multiplication, and subtraction. The default implementation is via 'Integer',+-- but a faster implementation can be provided instead. If provided, the+-- implementation must be correct for moduli in range @[1, 'Limit']@.+--+-- __WARNING:__ a naive implementaton is prone to arithmetic overflow and may+-- produce invalid results for moduli close to 'Limit'.+class Integral a => SaneIntegral a where+ type Limit a :: Maybe Nat+ -- | Given @n > 0@, @0 <= a < n@, and @0 <= b < n@, @'modAdd' n a b@+ -- computes @(a 'Prelude.+' b) \` 'mod' \` n@.+ modAdd :: a -> a -> a -> a+ modAdd n a b = fromInteger+ (modAdd (toInteger n) (toInteger a) (toInteger b) :: Integer)+ -- | Given @n > 0@, @0 <= a < n@, and @0 <= b < n@, @'modSub' n a b@+ -- computes @(a 'Prelude.-' b) \` 'mod' \` n@.+ modSub :: a -> a -> a -> a+ modSub n a b = fromInteger+ (modSub (toInteger n) (toInteger a) (toInteger b) :: Integer)+ -- | Given @n > 0@, @0 <= a < n@, and @0 <= b < n@, @'modMul' n a b@+ -- computes @(a 'Prelude.*' b) \` 'mod' \` n@.+ modMul :: a -> a -> a -> a+ modMul n a b = fromInteger+ (modMul (toInteger n) (toInteger a) (toInteger b) :: Integer)++instance SaneIntegral Integer where+ type Limit Integer = 'Nothing+ modAdd n a b = case a + b of+ r | r >= n -> r - n+ r -> r+ modSub n a b = if a >= b then a - b else n - b + a+ modMul n a b = (a * b) `mod` n++#if MIN_VERSION_base(4,8,0)+instance SaneIntegral Natural where+ type Limit Natural = 'Nothing+ modAdd n a b = case a + b of+ r | r >= n -> r - n+ r -> r+ modSub n a b = if a >= b then a - b else n - b + a+ modMul n a b = (a * b) `mod` n+#endif++instance SaneIntegral Word where+ type Limit Word = 'Just $(litT $ numTyLit $ toInteger (maxBound :: Word))++ modAdd (W# n) (W# a) (W# b) = W# (case plusWord2# a b of+ (# 0##, r #) | isTrue# (ltWord# r n) -> r+ (# _, r #) -> minusWord# r n)++ modSub (W# n) (W# a) (W# b) = W# (if isTrue# (leWord# b a)+ then minusWord# a b+ else plusWord# (minusWord# n b) a)++ modMul (W# n) (W# a) (W# b) = W# (case n of+ 0## -> error "modMul: division by zero"+ _ -> case timesWord2# a b of+ (# h, l #) -> case quotRemWord2# h l n of+ (# _, r #) -> r)++modAddViaWord :: (Num a, Integral a) => a -> a -> a -> a+modAddViaWord n a b = fromIntegral+ (modAdd (fromIntegral n) (fromIntegral a) (fromIntegral b) :: Word)++modSubViaWord :: (Num a, Integral a) => a -> a -> a -> a+modSubViaWord n a b = fromIntegral+ (modSub (fromIntegral n) (fromIntegral a) (fromIntegral b) :: Word)++modMulViaWord :: (Num a, Integral a) => a -> a -> a -> a+modMulViaWord n a b = fromIntegral+ (modMul (fromIntegral n) (fromIntegral a) (fromIntegral b) :: Word)++instance SaneIntegral Int where+ type Limit Int = 'Just $(litT $ numTyLit $ toInteger (maxBound :: Int))+ modAdd = modAddViaWord+ modSub = modSubViaWord+ modMul = modMulViaWord++instance SaneIntegral Word8 where+ type Limit Word8+ = 'Just $(litT $ numTyLit $ toInteger (maxBound :: Word8))+ modAdd = modAddViaWord+ modSub = modSubViaWord+ modMul = modMulViaWord++instance SaneIntegral Int8 where+ type Limit Int8+ = 'Just $(litT $ numTyLit $ toInteger (maxBound :: Int8))+ modAdd = modAddViaWord+ modSub = modSubViaWord+ modMul = modMulViaWord++instance SaneIntegral Word16 where+ type Limit Word16+ = 'Just $(litT $ numTyLit $ toInteger (maxBound :: Word16))+ modAdd = modAddViaWord+ modSub = modSubViaWord+ modMul = modMulViaWord++instance SaneIntegral Int16 where+ type Limit Int16+ = 'Just $(litT $ numTyLit $ toInteger (maxBound :: Int16))+ modAdd = modAddViaWord+ modSub = modSubViaWord+ modMul = modMulViaWord++instance SaneIntegral Word32 where+ type Limit Word32+ = 'Just $(litT $ numTyLit $ toInteger (maxBound :: Word32))+#if WORD_SIZE_IN_BITS >= 32+ modAdd = modAddViaWord+ modSub = modSubViaWord+ modMul = modMulViaWord+#endif++instance SaneIntegral Int32 where+ type Limit Int32+ = 'Just $(litT $ numTyLit $ toInteger (maxBound :: Int32))+#if WORD_SIZE_IN_BITS >= 32+ modAdd = modAddViaWord+ modSub = modSubViaWord+ modMul = modMulViaWord+#endif++instance SaneIntegral Word64 where+ type Limit Word64+ = 'Just $(litT $ numTyLit $ toInteger (maxBound :: Word64))+#if WORD_SIZE_IN_BITS >= 64+ modAdd = modAddViaWord+ modSub = modSubViaWord+ modMul = modMulViaWord+#endif++instance SaneIntegral Int64 where+ type Limit Int64+ = 'Just $(litT $ numTyLit $ toInteger (maxBound :: Int64))+#if WORD_SIZE_IN_BITS >= 64+ modAdd = modAddViaWord+ modSub = modSubViaWord+ modMul = modMulViaWord+#endif++class LeqMaybe (n :: Nat) (c :: Maybe Nat)+instance LeqMaybe n 'Nothing+instance n <= m => LeqMaybe n ('Just m)++-- | Ensures that the value of @n@ is representable in type @a@ (which should be+-- a 'SaneIntegral').+type Limited a (n :: Nat) = LeqMaybe n (Limit a)++-- | This class asserts that the value of @n@ is known at runtime, and that it+-- is representable in type @a@ (which should be a 'SaneIntegral').+--+-- At runtime it acts like an implicit parameter of type @a@, much like+-- 'KnownNat' is an implicit parameter of type 'Integer'.+class KnownIntegral a (n :: Nat) where+ intVal_ :: Tagged n a++instance (SaneIntegral a, Limited a n, KnownNat n) => KnownIntegral a n where+ intVal_ = Tagged $ fromInteger $ natVal (Proxy :: Proxy n)++-- | Reflect a type-level number into a term.+intVal :: forall n a proxy. KnownIntegral a n => proxy n -> a+intVal _ = unTagged (intVal_ :: Tagged n a)+{-# INLINABLE intVal #-}++-- | Recover a 'KnownNat' constraint from a 'KnownIntegral' constraint.+withIntegral+ :: forall a n r proxy1 proxy2. (SaneIntegral a, KnownIntegral a n)+ => proxy1 a -> proxy2 n -> (KnownNat n => r) -> r+withIntegral _ _ k = case someNatVal n of+ Nothing -> error $ "withIntegral: got KnowIntegral instance dictionary "+ ++ " for which toInteger returns " ++ show n+ Just (SomeNat (_ :: Proxy m)) -> case unsafeCoerce Refl :: n :~: m of+ Refl -> k+ where n = toInteger $ (intVal_ :: Tagged n a)+{-# INLINABLE withIntegral #-}++-- | Recover a 'Limited' constraint from a 'KnownIntegral' constraint.+withLimited+ :: forall a n r lim proxy1 proxy2. (Limit a ~ 'Just lim, KnownIntegral a n)+ => proxy1 a -> proxy2 n -> (Limited a n => r) -> r+withLimited _ _ k = case unsafeCoerce Refl :: (n <=? lim) :~: 'True of+ Refl -> k+{-# INLINABLE withLimited #-}++-- | Finite number type. The type @'Finite' a n@ is inhabited by exactly @n@+-- values from type @a@, in the range @[0, n)@ including @0@ but excluding @n@.+-- @a@ must be an instance of 'SaneIntegral' to use this type. Invariants:+--+-- prop> getFinite x < intVal x+-- prop> getFinite x >= 0+newtype Finite a (n :: Nat) = Finite a+ deriving (Eq, Ord, Ix)++type role Finite nominal nominal++-- | Convert an @a@ into a @'Finite' a@, throwing an error if the input is out+-- of bounds.+finite :: forall n a. (SaneIntegral a, KnownIntegral a n) => a -> Finite a n+finite x+ | x < n && x >= 0 = Finite x+ | otherwise = error $ "finite: Integral " ++ show (toInteger x)+ ++ " is not representable in Finite _ " ++ show (toInteger n)+ where n = intVal (Proxy :: Proxy n)+{-# INLINABLE finite #-}++-- | Convert a @'Finite' a@ into the corresponding @a@.+getFinite :: forall n a. Finite a n -> a+getFinite (Finite x) = x+{-# INLINABLE getFinite #-}++-- | Throws an error for @'Finite' _ 0@+instance (SaneIntegral a, KnownIntegral a n) => Bounded (Finite a n) where+ {-# SPECIALIZE instance KnownNat n => Bounded (Finite Integer n) #-}+#if MIN_VERSION_base(4,8,0)+ {-# SPECIALIZE instance KnownNat n => Bounded (Finite Natural n) #-}+#endif+ {-# SPECIALIZE instance KnownIntegral Word n => Bounded (Finite Word n) #-}+ {-# SPECIALIZE instance KnownIntegral Int n => Bounded (Finite Int n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Word8 n => Bounded (Finite Word8 n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Int8 n => Bounded (Finite Int8 n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Word16 n => Bounded (Finite Word16 n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Int16 n => Bounded (Finite Int16 n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Word32 n => Bounded (Finite Word32 n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Int32 n => Bounded (Finite Int32 n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Word64 n => Bounded (Finite Word64 n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Int64 n => Bounded (Finite Int64 n) #-}+ maxBound+ | n > 0 = Finite $ n - 1+ | otherwise = error "maxBound: Finite _ 0 is uninhabited"+ where n = intVal (Proxy :: Proxy n) :: a+ minBound+ | n > 0 = Finite 0+ | otherwise = error "minBound: Finite _ 0 is uninhabited"+ where n = intVal (Proxy :: Proxy n) :: a++instance (SaneIntegral a, KnownIntegral a n) => Enum (Finite a n) where+ {-# SPECIALIZE instance KnownNat n => Enum (Finite Integer n) #-}+#if MIN_VERSION_base(4,8,0)+ {-# SPECIALIZE instance KnownNat n => Enum (Finite Natural n) #-}+#endif+ {-# SPECIALIZE instance KnownIntegral Word n => Enum (Finite Word n) #-}+ {-# SPECIALIZE instance KnownIntegral Int n => Enum (Finite Int n) #-}+ {-# SPECIALIZE instance KnownIntegral Word8 n => Enum (Finite Word8 n) #-}+ {-# SPECIALIZE instance KnownIntegral Int8 n => Enum (Finite Int8 n) #-}+ {-# SPECIALIZE instance KnownIntegral Word16 n => Enum (Finite Word16 n) #-}+ {-# SPECIALIZE instance KnownIntegral Int16 n => Enum (Finite Int16 n) #-}+ {-# SPECIALIZE instance KnownIntegral Word32 n => Enum (Finite Word32 n) #-}+ {-# SPECIALIZE instance KnownIntegral Int32 n => Enum (Finite Int32 n) #-}+ {-# SPECIALIZE instance KnownIntegral Word64 n => Enum (Finite Word64 n) #-}+ {-# SPECIALIZE instance KnownIntegral Int64 n => Enum (Finite Int64 n) #-}+ succ (Finite x)+ | x == n - 1 = error "succ: bad argument"+ | otherwise = Finite $ succ x+ where n = intVal (Proxy :: Proxy n)+ pred (Finite x)+ | x == 0 = error "pred: bad argument"+ | otherwise = Finite $ pred x+ fromEnum = fromEnum . getFinite+ toEnum x+ | toInteger x < toInteger n && x >= 0 = Finite $ fromIntegral x+ | otherwise = error $ "toEnum: Int " ++ show x+ ++ " is not representable in Finite _ " ++ show (toInteger n)+ where n = intVal (Proxy :: Proxy n) :: a+ enumFrom x = enumFromTo x maxBound+ enumFromTo (Finite x) (Finite y) = Finite `fmap` enumFromTo x y+ enumFromThen x y+ = enumFromThenTo x y (if x >= y then minBound else maxBound)+ enumFromThenTo (Finite x) (Finite y) (Finite z)+ = Finite `fmap` enumFromThenTo x y z++instance Show a => Show (Finite a n) where+ showsPrec d (Finite x)+ = showParen (d > 9) $ showString "finite " . showsPrec 10 x++instance (Read a, SaneIntegral a, KnownIntegral a n) => Read (Finite a n) where+ readPrec = parens $ Text.ParserCombinators.ReadPrec.prec 10 $ do+ expectP (Ident "finite")+ x <- readPrec+ guard (x >= 0 && x < n)+ return $ Finite x+ where n = intVal (Proxy :: Proxy n)++-- | 'Prelude.+', 'Prelude.-', and 'Prelude.*' implement arithmetic modulo @n@.+-- The 'fromInteger' function raises an error for inputs outside of bounds.+instance (SaneIntegral a, KnownIntegral a n) => Num (Finite a n) where+ {-# SPECIALIZE instance KnownNat n => Num (Finite Integer n) #-}+#if MIN_VERSION_base(4,8,0)+ {-# SPECIALIZE instance KnownNat n => Num (Finite Natural n) #-}+#endif+ {-# SPECIALIZE instance KnownIntegral Word n => Num (Finite Word n) #-}+ {-# SPECIALIZE instance KnownIntegral Int n => Num (Finite Int n) #-}+ {-# SPECIALIZE instance KnownIntegral Word8 n => Num (Finite Word8 n) #-}+ {-# SPECIALIZE instance KnownIntegral Int8 n => Num (Finite Int8 n) #-}+ {-# SPECIALIZE instance KnownIntegral Word16 n => Num (Finite Word16 n) #-}+ {-# SPECIALIZE instance KnownIntegral Int16 n => Num (Finite Int16 n) #-}+ {-# SPECIALIZE instance KnownIntegral Word32 n => Num (Finite Word32 n) #-}+ {-# SPECIALIZE instance KnownIntegral Int32 n => Num (Finite Int32 n) #-}+ {-# SPECIALIZE instance KnownIntegral Word64 n => Num (Finite Word64 n) #-}+ {-# SPECIALIZE instance KnownIntegral Int64 n => Num (Finite Int64 n) #-}+ Finite x + Finite y = Finite $ modAdd n x y+ where n = intVal (Proxy :: Proxy n)+ Finite x - Finite y = Finite $ modSub n x y+ where n = intVal (Proxy :: Proxy n)+ Finite x * Finite y = Finite $ modMul n x y+ where n = intVal (Proxy :: Proxy n)+ abs fx = fx+ signum (Finite x) = Finite $ if x == 0 then 0 else 1+ fromInteger x+ | x < toInteger n && x >= 0 = Finite $ fromInteger x+ | otherwise = error $ "fromInteger: Integer " ++ show x+ ++ " is not representable in Finite _ " ++ show (toInteger n)+ where n = intVal (Proxy :: Proxy n) :: a++instance (SaneIntegral a, KnownIntegral a n) => Real (Finite a n) where+ {-# SPECIALIZE instance KnownNat n => Real (Finite Integer n) #-}+#if MIN_VERSION_base(4,8,0)+ {-# SPECIALIZE instance KnownNat n => Real (Finite Natural n) #-}+#endif+ {-# SPECIALIZE instance KnownIntegral Word n => Real (Finite Word n) #-}+ {-# SPECIALIZE instance KnownIntegral Int n => Real (Finite Int n) #-}+ {-# SPECIALIZE instance KnownIntegral Word8 n => Real (Finite Word8 n) #-}+ {-# SPECIALIZE instance KnownIntegral Int8 n => Real (Finite Int8 n) #-}+ {-# SPECIALIZE instance KnownIntegral Word16 n => Real (Finite Word16 n) #-}+ {-# SPECIALIZE instance KnownIntegral Int16 n => Real (Finite Int16 n) #-}+ {-# SPECIALIZE instance KnownIntegral Word32 n => Real (Finite Word32 n) #-}+ {-# SPECIALIZE instance KnownIntegral Int32 n => Real (Finite Int32 n) #-}+ {-# SPECIALIZE instance KnownIntegral Word64 n => Real (Finite Word64 n) #-}+ {-# SPECIALIZE instance KnownIntegral Int64 n => Real (Finite Int64 n) #-}+ toRational (Finite x) = toRational x++-- | 'quot' and 'rem' are the same as 'div' and 'mod' and they implement regular+-- division of numbers in the range @[0, n)@, __not__ modular inverses.+instance (SaneIntegral a, KnownIntegral a n) => Integral (Finite a n) where+ {-# SPECIALIZE instance KnownNat n => Integral (Finite Integer n) #-}+#if MIN_VERSION_base(4,8,0)+ {-# SPECIALIZE instance KnownNat n => Integral (Finite Natural n) #-}+#endif+ {-# SPECIALIZE instance KnownIntegral Word n => Integral (Finite Word n) #-}+ {-# SPECIALIZE instance KnownIntegral Int n => Integral (Finite Int n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Word8 n => Integral (Finite Word8 n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Int8 n => Integral (Finite Int8 n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Word16 n => Integral (Finite Word16 n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Int16 n => Integral (Finite Int16 n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Word32 n => Integral (Finite Word32 n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Int32 n => Integral (Finite Int32 n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Word64 n => Integral (Finite Word64 n) #-}+ {-# SPECIALIZE instance+ KnownIntegral Int64 n => Integral (Finite Int64 n) #-}+ quot (Finite x) (Finite y) = Finite $ quot x y+ rem (Finite x) (Finite y) = Finite $ rem x y+ quotRem (Finite x) (Finite y) = case quotRem x y of+ (q, r) -> (Finite q, Finite r)+ div (Finite x) (Finite y) = Finite $ div x y+ mod (Finite x) (Finite y) = Finite $ mod x y+ divMod (Finite x) (Finite y) = case divMod x y of+ (q, r) -> (Finite q, Finite r)+ toInteger (Finite x) = toInteger x++instance NFData a => NFData (Finite a n) where+ rnf (Finite x) = rnf x
test/Main.hs view
@@ -1,542 +1,1118 @@-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE AllowAmbiguousTypes #-}-module Main where--import Control.Exception-import Control.DeepSeq-import Data.List-import Data.Maybe-import Data.Proxy-import Data.Type.Equality-import GHC.TypeLits-import System.Exit-import Test.QuickCheck-import Unsafe.Coerce--import Data.Finite-import Data.Finite.Internal--instance KnownNat n => Arbitrary (Finite n) where- arbitrary- | natVal @n Proxy == 0 = discard- | otherwise = oneof- [ pure (Finite 0)- , pure (Finite $ natVal @n Proxy - 1)- , Finite . (`mod` natVal @n Proxy) <$> arbitrary- ]- shrink (Finite x) = mapMaybe packFinite $ shrink x--withNat' :: forall prop. Testable prop => Gen Integer -> (Integer -> [Integer]) -> (forall n. KnownNat n => (forall i. Num i => i) -> Proxy n -> prop) -> Property-withNat' gen shr prop = forAllShrinkBlind gen shr $ \n -> case someNatVal n of- Nothing -> counterexample "withNat" False- Just (SomeNat p) -> counterexample ("@" ++ show n) $ prop (fromInteger (natVal p)) p--withNat :: forall prop. Testable prop => (forall n. KnownNat n => (forall i. Num i => i) -> Proxy n -> prop) -> Property-withNat = withNat' (getNonNegative <$> arbitrary) (map getNonNegative . shrink . NonNegative)--withNatPos :: forall prop. Testable prop => (forall n. KnownNat n => (forall i. Num i => i) -> Proxy n -> prop) -> Property-withNatPos = withNat' (getPositive <$> arbitrary) (map getPositive . shrink . Positive)--unsafeWithKnownNat :: forall n prop. Testable prop => Integer -> (KnownNat n => prop) -> Property-unsafeWithKnownNat n prop = case someNatVal n of- Nothing -> counterexample "unsafeWithKnownNat: someNatVal" False- Just (SomeNat (_ :: Proxy n')) -> case unsafeCoerce Refl :: n :~: n' of- Refl -> property prop--newtype IneqCond (n :: Nat) (m :: Nat) = IneqCond ((n <= m) => Property)-unsafeWithInequality :: forall (n :: Nat) (m :: Nat) prop. Testable prop => ((n <= m) => prop) -> Property-unsafeWithInequality prop =- case unsafeCoerce (IneqCond @n @m $ property prop) :: IneqCond 0 1 of- IneqCond prop' -> prop'--prop_isvalid_under = withNat $ \_ (_ :: Proxy n) x ->- x < 0 ==> expectFailure $ isValidFinite @n (Finite x)-prop_isvalid_over = withNat $ \n (_ :: Proxy n) x ->- x >= n ==> expectFailure $ isValidFinite @n (Finite x)--prop_valid_finite = withNat $ \_ (_ :: Proxy n) x -> ioProperty $- evaluate (isValidFinite $ finite @n x)- `catch` \(_ :: ErrorCall) -> pure True-prop_getFinite_finite = withNat $ \_ (_ :: Proxy n) x -> ioProperty $- evaluate (getFinite (finite @n x) == x)- `catch` \(_ :: ErrorCall) -> pure True-prop_finite_getFinite = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x ->- finite (getFinite @n x) === x--prop_valid_maxBound = withNat $ \n (_ :: Proxy n) ->- n > 0 ==> isValidFinite (maxBound @(Finite n))-prop_maxBound_max = withNat $ \n (_ :: Proxy n) ->- property $ \x ->- n > 0 ==> maxBound @(Finite n) >= x--prop_valid_minBound = withNat $ \n (_ :: Proxy n) ->- n > 0 ==> isValidFinite (minBound @(Finite n))-prop_minBound_min = withNat $ \n (_ :: Proxy n) ->- property $ \x ->- n > 0 ==> minBound @(Finite n) <= x--prop_valid_toEnum = withNat $ \_ (_ :: Proxy n) x -> ioProperty $- evaluate (isValidFinite $ toEnum @(Finite n) x)- `catch` \(_ :: ErrorCall) -> pure True-prop_fromEnum_toEnum = withNat $ \_ (_ :: Proxy n) x -> ioProperty $- evaluate (fromEnum (toEnum @(Finite n) x) == x)- `catch` \(_ :: ErrorCall) -> pure True-prop_toEnum_fromEnum = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x ->- toEnum @(Finite n) (fromEnum x) == x--prop_valid_enumFrom = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x ->- all isValidFinite $ enumFrom @(Finite n) x-prop_getFinite_enumFrom = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x ->- map getFinite (enumFrom @(Finite n) x)- === takeWhile (isJust . packFinite @n) (enumFrom (getFinite x))--prop_valid_enumFromTo = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- all isValidFinite $ enumFromTo @(Finite n) x y-prop_getFinite_enumFromTo = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- map getFinite (enumFromTo @(Finite n) x y)- === enumFromTo (getFinite x) (getFinite y)--prop_valid_enumFromThen = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- x /= y ==> all isValidFinite $ enumFromThen @(Finite n) x y-prop_getFinite_enumFromThen = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- x /= y ==> map getFinite (enumFromThen @(Finite n) x y)- === takeWhile (isJust . packFinite @n) (enumFromThen (getFinite x) (getFinite y))--prop_valid_enumFromThenTo = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y z ->- x /= y ==> all isValidFinite $ enumFromThenTo @(Finite n) x y z-prop_getFinite_enumFromThenTo = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y z ->- x /= y ==> map getFinite (enumFromThenTo @(Finite n) x y z)- === enumFromThenTo (getFinite x) (getFinite y) (getFinite z)--prop_nonint_succ = withNat' genBig shrinkBig $ \_ (_ :: Proxy n) ->- forAllShrink genBig shrinkBig $ \x ->- case packFinite @n $ succ x of- Nothing -> discard- Just y -> y === succ (finite x)- where- big = toInteger (maxBound :: Int)- genBig = (big +) . getNonNegative <$> arbitrary- shrinkBig = map ((big +) . getNonNegative) . shrink . NonNegative . subtract big--prop_valid_read = withNatPos $ \_ (_ :: Proxy n) ->- withNatPos $ \_ (_ :: Proxy m) ->- property $ \x -> ioProperty $- evaluate (isValidFinite $ read @(Finite n) (show @(Finite m) x))- `catch` \(_ :: ErrorCall) -> pure True-prop_read_show = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x ->- read (show @(Finite n) x) === x--prop_valid_plus = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- isValidFinite @n $ x + y-prop_getFinite_plus = withNatPos $ \n (_ :: Proxy n) ->- property $ \x y ->- (getFinite @n (x + y) - (getFinite x + getFinite y)) `mod` n === 0--prop_valid_minus = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- isValidFinite @n $ x - y-prop_getFinite_minus = withNatPos $ \n (_ :: Proxy n) ->- property $ \x y ->- (getFinite @n (x - y) - (getFinite x - getFinite y)) `mod` n === 0--prop_valid_times = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- isValidFinite @n $ x * y-prop_getFinite_times = withNatPos $ \n (_ :: Proxy n) ->- property $ \x y ->- (getFinite @n (x * y) - (getFinite x * getFinite y)) `mod` n === 0--prop_valid_negate = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x ->- isValidFinite @n $ -x-prop_getFinite_negate = withNatPos $ \n (_ :: Proxy n) ->- property $ \x ->- (getFinite @n (-x) - (- getFinite x)) `mod` n === 0--prop_valid_abs = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x ->- isValidFinite @n $ abs x-prop_getFinite_abs = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x ->- getFinite @n (abs x) === abs (getFinite x)--prop_valid_signum = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x -> ioProperty $- evaluate (isValidFinite @n $ signum x)- `catch` \(_ :: ErrorCall) -> pure True--prop_getFinite_signum = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x -> ioProperty $- evaluate (getFinite @n (signum x) == signum (getFinite x))- `catch` \(_ :: ErrorCall) -> pure True--prop_valid_fromInteger = withNatPos $ \_ (_ :: Proxy n) x -> ioProperty $- evaluate (isValidFinite $ fromInteger @(Finite n) x)- `catch` \(_ :: ErrorCall) -> pure True-prop_toInteger_fromInteger = withNat $ \_ (_ :: Proxy n) x -> ioProperty $- evaluate (toInteger (fromInteger @(Finite n) x) == x)- `catch` \(_ :: ErrorCall) -> pure True-prop_fromInteger_toInteger = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x ->- fromInteger (toInteger @(Finite n) x) === x--prop_valid_quot = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- y /= 0 ==> isValidFinite @n $ x `quot` y-prop_getFinite_quot = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- y /= 0 ==> getFinite @n (x `quot` y) === getFinite x `quot` getFinite y--prop_valid_rem = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- y /= 0 ==> isValidFinite @n $ x `rem` y-prop_getFinite_rem = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- y /= 0 ==> getFinite @n (x `rem` y) === getFinite x `rem` getFinite y--prop_valid_div = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- y /= 0 ==> isValidFinite @n $ x `div` y-prop_getFinite_div = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- y /= 0 ==> getFinite @n (x `div` y) === getFinite x `div` getFinite y--prop_valid_mod = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- y /= 0 ==> isValidFinite @n $ x `mod` y-prop_getFinite_mod = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x y ->- y /= 0 ==> getFinite @n (x `mod` y) === getFinite x `mod` getFinite y--prop_force = withNat $ \_ (_ :: Proxy n) ->- expectFailure $ rnf @(Finite n) (error "Expected exception") `seq` True--prop_valid_packFinite = withNat $ \_ (_ :: Proxy n) x ->- maybe True isValidFinite $ packFinite @n x-prop_getFinite_packFinite = withNat $ \_ (_ :: Proxy n) x ->- maybe (property True) ((x ===) . getFinite) $ packFinite @n x-prop_finite_packFinite = withNat $ \_ (_ :: Proxy n) x -> ioProperty $- case packFinite @n x of- Nothing -> (evaluate (finite @n x) >> pure False)- `catch` \(_ :: ErrorCall) -> pure True- Just y -> evaluate (y == finite x)--prop_valid_finites = withNat $ \_ (_ :: Proxy n) ->- all isValidFinite $ finites @n-prop_finites_minMax = withNatPos $ \_ (_ :: Proxy n) ->- minBound `elem` finites @n .&&. maxBound `elem` finites @n-prop_finites_ordered = withNat $ \_ (_ :: Proxy n) ->- finites @n === sort finites-prop_finites_all = withNat $ \_ (_ :: Proxy n) ->- property $ \x ->- x {- could be discard -} `seq` x `elem` finites @n--prop_valid_modulo = withNatPos $ \_ (_ :: Proxy n) x ->- isValidFinite $ modulo @n x-prop_getFinite_modulo = withNatPos $ \n (_ :: Proxy n) x ->- (getFinite (modulo @n x) - x) `mod` n === 0---prop_getFinite_equals = withNatPos $ \_ (_ :: Proxy n) ->- withNatPos $ \_ (_ :: Proxy m) ->- property $ \x y ->- (x `equals` y) === (getFinite @n x == getFinite @m y)--prop_getFinite_cmp = withNatPos $ \_ (_ :: Proxy n) ->- withNatPos $ \_ (_ :: Proxy m) ->- property $ \x y ->- (x `cmp` y) === (getFinite @n x `compare` getFinite @m y)--prop_valid_natToFinite = withNat $ \n (_ :: Proxy n) ->- withNatPos $ \m (_ :: Proxy m) ->- n + 1 <= m ==> unsafeWithInequality @(n + 1) @m @Bool $- isValidFinite $ natToFinite @n @m Proxy-prop_getFinite_natToFinite = withNat $ \n (_ :: Proxy n) ->- withNatPos $ \m (_ :: Proxy m) ->- n + 1 <= m ==> unsafeWithInequality @(n + 1) @m @Property $- getFinite (natToFinite @n @m Proxy) === natVal @n Proxy--prop_valid_weaken = withNatPos $ \n (_ :: Proxy n) ->- unsafeWithKnownNat @(n + 1) (n + 1) $- property $ \x ->- isValidFinite $ weaken @n x-prop_finites_weaken = withNat $ \n (_ :: Proxy n) ->- unsafeWithKnownNat @(n + 1) (n + 1) $- map (weaken @n) finites === init finites--prop_valid_strengthen = withNat $ \n (_ :: Proxy n) ->- unsafeWithKnownNat @(n + 1) (n + 1) $- property $ \x ->- maybe True isValidFinite $ strengthen @n x-prop_finites_strengthen = withNat $ \n (_ :: Proxy n) ->- unsafeWithKnownNat @(n + 1) (n + 1) $- map (strengthen @n) finites === map Just finites ++ [Nothing]--prop_valid_shift = withNatPos $ \n (_ :: Proxy n) ->- unsafeWithKnownNat @(n + 1) (n + 1) $- property $ \x ->- isValidFinite $ shift @n x-prop_finites_shift = withNat $ \n (_ :: Proxy n) ->- unsafeWithKnownNat @(n + 1) (n + 1) $- map (shift @n) finites === tail finites--prop_valid_unshift = withNat $ \n (_ :: Proxy n) ->- unsafeWithKnownNat @(n + 1) (n + 1) $- property $ \x ->- maybe True isValidFinite $ unshift @n x-prop_finites_unshift = withNat $ \n (_ :: Proxy n) ->- unsafeWithKnownNat @(n + 1) (n + 1) $- map (unshift @n) finites === [Nothing] ++ map Just finites--prop_valid_weakenN = withNatPos $ \n (_ :: Proxy n) ->- withNatPos $ \m (_ :: Proxy m) ->- n <= m ==> unsafeWithInequality @n @m @Property $- property $ \x ->- isValidFinite $ weakenN @n @m x-prop_finites_weakenN = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- n <= m ==> unsafeWithInequality @n @m @Property $- map (weakenN @n @m) finites === take n finites--prop_valid_strengthenN = withNat $ \_ (_ :: Proxy n) ->- withNatPos $ \_ (_ :: Proxy m) ->- property $ \x ->- maybe True isValidFinite $ strengthenN @n @m x-prop_finites_strengthenN = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- map (strengthenN @m @n) finites === take n (map Just finites) ++ replicate (n - m) Nothing--prop_valid_shiftN = withNatPos $ \n (_ :: Proxy n) ->- withNatPos $ \m (_ :: Proxy m) ->- n <= m ==> unsafeWithInequality @n @m @Property $- property $ \x ->- isValidFinite $ shiftN @n @m x-prop_finites_shiftN = withNat $ \n (_ :: Proxy n) ->- withNatPos $ \m (_ :: Proxy m) ->- n <= m ==> unsafeWithInequality @n @m @Property $- map (shiftN @n @m) finites === drop (m - n) finites--prop_valid_unshiftN = withNatPos $ \_ (_ :: Proxy n) ->- withNat $ \_ (_ :: Proxy m) ->- property $ \x ->- maybe True isValidFinite $ unshiftN @n @m x-prop_finites_unshiftN = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- map (unshiftN @m @n) finites === replicate (n - m) Nothing ++ drop (m - n) (map Just finites)--prop_valid_weakenProxy = withNatPos $ \n (_ :: Proxy n) ->- withNat $ \k (_ :: Proxy k) ->- unsafeWithKnownNat @(n + k) (n + k) $- property $ \x ->- isValidFinite $ weakenProxy @Proxy @k @n Proxy x-prop_finites_weakenProxy = withNat $ \n (_ :: Proxy n) ->- withNat $ \k (_ :: Proxy k) ->- unsafeWithKnownNat @(n + k) (n + k) $- map (weakenProxy @Proxy @k @n Proxy) finites === take n finites--prop_valid_strengthenProxy = withNat $ \n (_ :: Proxy n) ->- withNat $ \k (_ :: Proxy k) ->- unsafeWithKnownNat @(n + k) (n + k) $- property $ \x ->- maybe True isValidFinite $ strengthenProxy @n @Proxy @k Proxy x-prop_finites_strengthenProxy = withNat $ \n (_ :: Proxy n) ->- withNat $ \k (_ :: Proxy k) ->- unsafeWithKnownNat @(n + k) (n + k) $- map (strengthenProxy @n @Proxy @k Proxy) finites === take n (map Just finites) ++ replicate k Nothing--prop_valid_shiftProxy = withNatPos $ \n (_ :: Proxy n) ->- withNat $ \k (_ :: Proxy k) ->- unsafeWithKnownNat @(n + k) (n + k) $- property $ \x ->- isValidFinite $ shiftProxy @k @Proxy @n Proxy x-prop_finites_shiftProxy = withNat $ \n (_ :: Proxy n) ->- withNat $ \k (_ :: Proxy k) ->- unsafeWithKnownNat @(n + k) (n + k) $- map (shiftProxy @k @Proxy @n Proxy) finites === drop k finites--prop_valid_unshiftProxy = withNat $ \n (_ :: Proxy n) ->- withNat $ \k (_ :: Proxy k) ->- unsafeWithKnownNat @(n + k) (n + k) $- property $ \x ->- maybe True isValidFinite $ unshiftProxy @k @Proxy @n Proxy x-prop_finites_unshiftProxy = withNat $ \n (_ :: Proxy n) ->- withNat $ \k (_ :: Proxy k) ->- unsafeWithKnownNat @(n + k) (n + k) $- map (unshiftProxy @k @Proxy @n Proxy) finites === replicate k Nothing ++ map Just finites--prop_strengthen_weaken = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x ->- strengthen @n (weaken x) === Just x-prop_weaken_strengthen = withNat $ \n (_ :: Proxy n) ->- unsafeWithKnownNat @(n + 1) (n + 1) $- property $ \x ->- maybe True (== x) (weaken @n <$> strengthen x)--prop_unshift_shift = withNatPos $ \_ (_ :: Proxy n) ->- property $ \x ->- unshift @n (shift x) === Just x-prop_shift_unshift = withNat $ \n (_ :: Proxy n) ->- unsafeWithKnownNat @(n + 1) (n + 1) $- property $ \x ->- maybe True (== x) (shift @n <$> unshift x)--prop_strengthenN_weakenN = withNatPos $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- m <= n ==> unsafeWithInequality @m @n @Property $- property $ \x ->- strengthenN @m @n (weakenN x) === Just x-prop_weakenN_strengthenN = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- n <= m ==> unsafeWithInequality @n @m @Property $- property $ \x ->- maybe True (== x) (weakenN @n @m <$> strengthenN x)--prop_unshiftN_shiftN = withNatPos $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- m <= n ==> unsafeWithInequality @m @n @Property $- property $ \x ->- unshiftN @m @n (shiftN x) === Just x-prop_shiftN_unshiftN = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- n <= m ==> unsafeWithInequality @n @m @Property $- property $ \x ->- maybe True (== x) (shiftN @n @m <$> unshiftN x)--prop_strengthenProxy_weakenProxy = withNatPos $ \_ (_ :: Proxy n) ->- withNat $ \_ (_ :: Proxy k) ->- property $ \x ->- strengthenProxy @n @Proxy @k Proxy (weakenProxy Proxy x) === Just x-prop_weakenProxy_strengthenProxy = withNat $ \n (_ :: Proxy n) ->- withNat $ \k (_ :: Proxy k) ->- unsafeWithKnownNat @(n + k) (n + k) $- property $ \x ->- maybe True (== x) (weakenProxy @Proxy @k @n Proxy <$> strengthenProxy Proxy x)--prop_unshiftProxy_shiftProxy = withNatPos $ \_ (_ :: Proxy n) ->- withNat $ \_ (_ :: Proxy k) ->- property $ \x ->- unshiftProxy @k @Proxy @n Proxy (shiftProxy Proxy x) === Just x-prop_shiftProxy_unshiftProxy = withNat $ \n (_ :: Proxy n) ->- withNat $ \k (_ :: Proxy k) ->- unsafeWithKnownNat @(n + k) (n + k) $- property $ \x ->- maybe True (== x) (shiftProxy @k @Proxy @n Proxy <$> unshiftProxy Proxy x)--prop_valid_add = withNatPos $ \n (_ :: Proxy n) ->- withNatPos $ \m (_ :: Proxy m) ->- unsafeWithKnownNat @(n + m) (n + m) $- property $ \x y ->- isValidFinite $ add @n @m x y-prop_getFinite_add = withNatPos $ \_ (_ :: Proxy n) ->- withNatPos $ \_ (_ :: Proxy m) ->- property $ \x y ->- getFinite (add @n @m x y) === getFinite x + getFinite y--prop_valid_sub = withNatPos $ \_ (_ :: Proxy n) ->- withNatPos $ \_ (_ :: Proxy m) ->- property $ \x y ->- either isValidFinite isValidFinite $ sub @n @m x y-prop_getFinite_sub = withNatPos $ \_ (_ :: Proxy n) ->- withNatPos $ \_ (_ :: Proxy m) ->- property $ \x y ->- either (negate . getFinite) getFinite (sub @n @m x y) === getFinite x - getFinite y-prop_sub_Left_0 = withNatPos $ \_ (_ :: Proxy n) ->- withNatPos $ \_ (_ :: Proxy m) ->- property $ \x y ->- sub @n @m x y =/= Left 0--prop_valid_multiply = withNatPos $ \n (_ :: Proxy n) ->- withNatPos $ \m (_ :: Proxy m) ->- unsafeWithKnownNat @(n GHC.TypeLits.* m) (n * m) $- property $ \x y ->- isValidFinite $ multiply @n @m x y-prop_getFinite_multiply = withNatPos $ \_ (_ :: Proxy n) ->- withNatPos $ \_ (_ :: Proxy m) ->- property $ \x y ->- getFinite (multiply @n @m x y) === getFinite x * getFinite y--prop_valid_combineSum = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- unsafeWithKnownNat @(n + m) (n + m) $- property $ \x ->- isValidFinite $ combineSum @n @m x-prop_finites_combineSum = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- unsafeWithKnownNat @(n + m) (n + m) $- map (combineSum @n @m) (map Left finites ++ map Right finites) === finites--prop_valid_combineProduct = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- unsafeWithKnownNat @(n GHC.TypeLits.* m) (n * m) $- property $ \x ->- isValidFinite (combineProduct @n @m x)-prop_finites_combineProduct = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- unsafeWithKnownNat @(n GHC.TypeLits.* m) (n * m) $- map (combineProduct @n @m) [(x, y) | y <- finites, x <- finites] === finites--prop_valid_separateSum = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- unsafeWithKnownNat @(n + m) (n + m) $- property $ \x ->- either isValidFinite isValidFinite $ separateSum @n @m x-prop_finites_separateSum = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- unsafeWithKnownNat @(n + m) (n + m) $- map (separateSum @n @m) finites === map Left finites ++ map Right finites--prop_valid_separateProduct = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- unsafeWithKnownNat @(n GHC.TypeLits.* m) (n * m) $- property $ \x ->- x {- could be discard -} `seq` isValidFinite (fst $ separateProduct @n @m x)- .&&. isValidFinite (snd $ separateProduct @n @m x)-prop_finites_separateProduct = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- unsafeWithKnownNat @(n GHC.TypeLits.* m) (n * m) $- map (separateProduct @n @m) finites === [(x, y) | y <- finites, x <- finites]--prop_combineSum_separateSum = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- unsafeWithKnownNat @(n + m) (n + m) $- property $ \x ->- combineSum @n @m (separateSum x) === x-prop_separateSum_combineSum = withNat $ \_ (_ :: Proxy n) ->- withNat $ \_ (_ :: Proxy m) ->- property $ \x ->- separateSum @n @m (combineSum x) === x--prop_combineProduct_separateProduct = withNat $ \n (_ :: Proxy n) ->- withNat $ \m (_ :: Proxy m) ->- unsafeWithKnownNat @(n GHC.TypeLits.* m) (n * m) $- property $ \x ->- x {- could be discard -} `seq` combineProduct @n @m (separateProduct x) === x-prop_separateProduct_combineProduct = withNat $ \_ (_ :: Proxy n) ->- withNat $ \_ (_ :: Proxy m) ->- property $ \x ->- force x {- could be discard -} `seq` separateProduct @n @m (combineProduct x) === x+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+module Main where++import Control.Exception+import Control.DeepSeq+import Control.Monad+import Data.Bifunctor+import Data.Int+import Data.List+import Data.Maybe+import Data.Proxy+import Data.Type.Equality+import Data.Typeable+import Data.Void+import Data.Word+import GHC.TypeLits+import System.Exit+import Test.QuickCheck hiding (Small)+import Unsafe.Coerce+import Numeric.Natural++import Debug.Trace++import Data.Finite.Integral+import Data.Finite.Internal.Integral++newtype SmallNonNeg a = SmallNonNeg { getSmallNonNeg :: a }+ deriving (Show)++instance (Integral a, Arbitrary a) => Arbitrary (SmallNonNeg a) where+ arbitrary = SmallNonNeg <$> arbitrarySizedNatural+ shrink (SmallNonNeg x) = SmallNonNeg <$> shrink x++instance Arbitrary Natural where+ arbitrary = fromInteger . getNonNegative <$> arbitrary++instance CoArbitrary Natural where+ coarbitrary n = coarbitrary (toInteger n)++newtype Small a n = Small (Finite a n)+ deriving (Show)++newtype Big a n = Big (Finite a n)+ deriving (Show)++newtype Edgy a n = Edgy (Finite a n)+ deriving (Show)++instance+ (Arbitrary a, SaneIntegral a, KnownIntegral a n)+ => Arbitrary (Small a n) where+ arbitrary+ | intVal @n @a Proxy == 0 = discard+ | otherwise = Small . Finite . (`mod` n)+ . getSmallNonNeg <$> arbitrary+ where n = intVal @n Proxy+ shrink (Small (Finite x)) = Small <$> mapMaybe packFinite (shrink x)++instance+ (Arbitrary a, SaneIntegral a, KnownIntegral a n)+ => Arbitrary (Big a n) where+ arbitrary+ | intVal @n @a Proxy == 0 = discard+ | otherwise = Big . Finite . ((n - 1) -) . (`mod` n)+ . getSmallNonNeg <$> arbitrary+ where n = intVal @n Proxy+ shrink (Big (Finite x)) = Big <$> mapMaybe packFinite (shrink x)++instance CoArbitrary a => CoArbitrary (Big a n) where+ coarbitrary (Big (Finite x)) = coarbitrary x++instance+ (Arbitrary a, SaneIntegral a, KnownIntegral a n)+ => Arbitrary (Edgy a n) where+ arbitrary+ | intVal @n @a Proxy == 0 = discard+ | otherwise = Edgy . Finite <$> oneof+ [ (`mod` n) . getSmallNonNeg <$> arbitrary+ , ((n - 1) -) . (`mod` n) . getSmallNonNeg <$> arbitrary+ ]+ where n = intVal @n Proxy+ shrink (Edgy (Finite x)) = Edgy <$> mapMaybe packFinite (shrink x)++data SLimited a where+ SLimited :: (Limited a n, KnownNat n) => Proxy n -> SLimited a++mkLimited+ :: forall a lim. (Limit a ~ 'Just lim, KnownNat lim)+ => Integer -> Maybe (SLimited a)+mkLimited n = case someNatVal n of+ Just (SomeNat (p :: Proxy b))+ | n <= natVal @lim Proxy+ , Refl :: (b <=? lim) :~: 'True <- unsafeCoerce Refl+ -> Just $ SLimited p+ _ -> Nothing++mkUnlimited+ :: forall a. Limit a ~ 'Nothing+ => Integer -> Maybe (SLimited a)+mkUnlimited n = case someNatVal n of+ Just (SomeNat p) -> Just $ SLimited p+ _ -> Nothing++genSmall, genOver7, genOver8, genOver15, genOver16, genOver31, genOver32,+ genOver63, genOver64, genOverI, genOverW, genUnder7, genUnder8, genUnder15,+ genUnder16, genUnder32, genUnder63, genUnder64, genUnderI, genUnderW+ :: Gen Integer+genSmall = getNonNegative <$> arbitrary+genOver7 = (toInteger (maxBound @Int8) +) <$> genSmall+genOver8 = (toInteger (maxBound @Word8) +) <$> genSmall+genOver15 = (toInteger (maxBound @Int16) +) <$> genSmall+genOver16 = (toInteger (maxBound @Word16) +) <$> genSmall+genOver31 = (toInteger (maxBound @Int32) +) <$> genSmall+genOver32 = (toInteger (maxBound @Word32) +) <$> genSmall+genOver63 = (toInteger (maxBound @Int64) +) <$> genSmall+genOver64 = (toInteger (maxBound @Word64) +) <$> genSmall+genOverI = (toInteger (maxBound @Int) +) <$> genSmall+genOverW = (toInteger (maxBound @Word) +) <$> genSmall+genUnder7 = ((toInteger (maxBound @Int8) -) <$> genSmall) `suchThat` (>= 0)+genUnder8 = ((toInteger (maxBound @Word8) -) <$> genSmall) `suchThat` (>= 0)+genUnder15 = ((toInteger (maxBound @Int16) -) <$> genSmall) `suchThat` (>= 0)+genUnder16 = ((toInteger (maxBound @Word16) -) <$> genSmall) `suchThat` (>= 0)+genUnder31 = ((toInteger (maxBound @Int32) -) <$> genSmall) `suchThat` (>= 0)+genUnder32 = ((toInteger (maxBound @Word32) -) <$> genSmall) `suchThat` (>= 0)+genUnder63 = ((toInteger (maxBound @Int64) -) <$> genSmall) `suchThat` (>= 0)+genUnder64 = ((toInteger (maxBound @Word64) -) <$> genSmall) `suchThat` (>= 0)+genUnderI = ((toInteger (maxBound @Int) -) <$> genSmall) `suchThat` (>= 0)+genUnderW = ((toInteger (maxBound @Word) -) <$> genSmall) `suchThat` (>= 0)++instance Arbitrary (SLimited Integer) where+ arbitrary = oneof+ [ genSmall, genUnder7, genOver7, genUnder8, genOver8, genUnder15+ , genOver15, genUnder16, genOver16, genUnder31, genOver31, genUnder32+ , genOver32, genUnder63, genOver63, genUnder64, genOver64, genUnderI+ , genOverI, genUnderW, genOverW ]+ `suchThatMap` mkUnlimited+ shrink (SLimited p) = mapMaybe mkUnlimited $ shrink $ natVal p++instance Arbitrary (SLimited Natural) where+ arbitrary = oneof+ [ genSmall, genUnder7, genOver7, genUnder8, genOver8, genUnder15+ , genOver15, genUnder16, genOver16, genUnder31, genOver31, genUnder32+ , genOver32, genUnder63, genOver63, genUnder64, genOver64, genUnderI+ , genOverI, genUnderW, genOverW ]+ `suchThatMap` mkUnlimited+ shrink (SLimited p) = mapMaybe mkUnlimited $ shrink $ natVal p++instance Arbitrary (SLimited Word) where+ arbitrary = oneof+ [ genSmall, genUnder7, genOver7, genUnder8, genOver8, genUnder15+ , genOver15, genUnder16, genOver16, genUnder31, genOver31, genUnder32+ , genOver32, genUnder63, genOver63, genUnder64, genOver64, genUnderI+ , genOverI, genUnderW ]+ `suchThatMap` mkLimited+ shrink (SLimited p) = mapMaybe mkLimited $ shrink $ natVal p++instance Arbitrary (SLimited Int) where+ arbitrary = oneof+ [ genSmall, genUnder7, genOver7, genUnder8, genOver8, genUnder15+ , genOver15, genUnder16, genOver16, genUnder31, genOver31, genUnder32+ , genOver32, genUnder63, genOver63, genUnder64, genOver64, genUnderI ]+ `suchThatMap` mkLimited+ shrink (SLimited p) = mapMaybe mkLimited $ shrink $ natVal p++instance Arbitrary (SLimited Word8) where+ arbitrary = oneof+ [ genSmall, genUnder7, genOver7, genUnder8 ]+ `suchThatMap` mkLimited+ shrink (SLimited p) = mapMaybe mkLimited $ shrink $ natVal p++instance Arbitrary (SLimited Int8) where+ arbitrary = oneof+ [ genSmall, genUnder7 ]+ `suchThatMap` mkLimited+ shrink (SLimited p) = mapMaybe mkLimited $ shrink $ natVal p++instance Arbitrary (SLimited Word16) where+ arbitrary = oneof+ [ genSmall, genUnder7, genOver7, genUnder8, genOver8, genUnder15+ , genOver15, genUnder16 ]+ `suchThatMap` mkLimited+ shrink (SLimited p) = mapMaybe mkLimited $ shrink $ natVal p++instance Arbitrary (SLimited Int16) where+ arbitrary = oneof+ [ genSmall, genUnder7, genOver7, genUnder8, genOver8, genUnder15 ]+ `suchThatMap` mkLimited+ shrink (SLimited p) = mapMaybe mkLimited $ shrink $ natVal p++instance Arbitrary (SLimited Word32) where+ arbitrary = oneof+ [ genSmall, genUnder7, genOver7, genUnder8, genOver8, genUnder15+ , genOver15, genUnder16, genOver16, genUnder31, genOver31, genUnder32 ]+ `suchThatMap` mkLimited+ shrink (SLimited p) = mapMaybe mkLimited $ shrink $ natVal p++instance Arbitrary (SLimited Int32) where+ arbitrary = oneof+ [ genSmall, genUnder7, genOver7, genUnder8, genOver8, genUnder15+ , genOver15, genUnder16, genOver16, genUnder31 ]+ `suchThatMap` mkLimited+ shrink (SLimited p) = mapMaybe mkLimited $ shrink $ natVal p++instance Arbitrary (SLimited Word64) where+ arbitrary = oneof+ [ genSmall, genUnder7, genOver7, genUnder8, genOver8, genUnder15+ , genOver15, genUnder16, genOver16, genUnder31, genOver31, genUnder32+ , genOver32, genUnder63, genOver63, genUnder64, genOverI, genUnderW+ , genOverW ]+ `suchThatMap` mkLimited+ shrink (SLimited p) = mapMaybe mkLimited $ shrink $ natVal p++instance Arbitrary (SLimited Int64) where+ arbitrary = oneof+ [ genSmall, genUnder7, genOver7, genUnder8, genOver8, genUnder15+ , genOver15, genUnder16, genOver16, genUnder31, genOver31, genUnder32+ , genOver32, genUnder63, genUnderI, genOverI, genUnderW, genOverW ]+ `suchThatMap` mkLimited+ shrink (SLimited p) = mapMaybe mkLimited $ shrink $ natVal p++newtype SmallLimited a = SmallLimited { getSmallLimited :: SLimited a }++instance Arbitrary (SmallLimited Integer) where+ arbitrary = SmallLimited <$> genSmall `suchThatMap` mkUnlimited+ shrink = map SmallLimited . shrink . getSmallLimited++instance Arbitrary (SmallLimited Natural) where+ arbitrary = SmallLimited <$> genSmall `suchThatMap` mkUnlimited+ shrink = map SmallLimited . shrink . getSmallLimited++instance Arbitrary (SmallLimited Word) where+ arbitrary = SmallLimited <$> genSmall `suchThatMap` mkLimited+ shrink = map SmallLimited . shrink . getSmallLimited++instance Arbitrary (SmallLimited Int) where+ arbitrary = SmallLimited <$> genSmall `suchThatMap` mkLimited+ shrink = map SmallLimited . shrink . getSmallLimited++instance Arbitrary (SmallLimited Word8) where+ arbitrary = SmallLimited <$> genSmall `suchThatMap` mkLimited+ shrink = map SmallLimited . shrink . getSmallLimited++instance Arbitrary (SmallLimited Int8) where+ arbitrary = SmallLimited <$> genSmall `suchThatMap` mkLimited+ shrink = map SmallLimited . shrink . getSmallLimited++instance Arbitrary (SmallLimited Word16) where+ arbitrary = SmallLimited <$> genSmall `suchThatMap` mkLimited+ shrink = map SmallLimited . shrink . getSmallLimited++instance Arbitrary (SmallLimited Int16) where+ arbitrary = SmallLimited <$> genSmall `suchThatMap` mkLimited+ shrink = map SmallLimited . shrink . getSmallLimited++instance Arbitrary (SmallLimited Word32) where+ arbitrary = SmallLimited <$> genSmall `suchThatMap` mkLimited+ shrink = map SmallLimited . shrink . getSmallLimited++instance Arbitrary (SmallLimited Int32) where+ arbitrary = SmallLimited <$> genSmall `suchThatMap` mkLimited+ shrink = map SmallLimited . shrink . getSmallLimited++instance Arbitrary (SmallLimited Word64) where+ arbitrary = SmallLimited <$> genSmall `suchThatMap` mkLimited+ shrink = map SmallLimited . shrink . getSmallLimited++instance Arbitrary (SmallLimited Int64) where+ arbitrary = SmallLimited <$> genSmall `suchThatMap` mkLimited+ shrink = map SmallLimited . shrink . getSmallLimited++type Good a =+ ( Show a+ , Read a+ , NFData a+ , Typeable a+ , SaneIntegral a+ , Arbitrary a+ , Arbitrary (SLimited a)+ , Arbitrary (SmallLimited a)+ , CoArbitrary a+ )++data SType where+ SType :: Good a => Proxy a -> SType++forType :: forall prop. Testable prop+ => (forall a. Good a => Proxy a -> prop)+ -> Property+forType prop = forAllBlind gen $ \case+ (name, SType p) -> counterexample @prop ("@" ++ name) $ prop p+ where+ gen = elements+ [ ("Integer", SType @Integer Proxy)+ , ("Natural", SType @Natural Proxy)+ , ("Word", SType @Word Proxy)+ , ("Int", SType @Int Proxy)+ , ("Word8", SType @Word8 Proxy)+ , ("Int8", SType @Int8 Proxy)+ , ("Word16", SType @Word16 Proxy)+ , ("Int16", SType @Int16 Proxy)+ , ("Word32", SType @Word32 Proxy)+ , ("Int32", SType @Int32 Proxy)+ , ("Word64", SType @Word64 Proxy)+ , ("Int64", SType @Int64 Proxy)+ ]++forLimit'+ :: forall a. SaneIntegral a+ => Gen (SLimited a)+ -> (SLimited a -> [SLimited a])+ -> (forall n. (KnownIntegral a n, Limited a n)+ => (forall i. Num i => i) -> Proxy n -> Property)+ -> Property+forLimit' gen shr prop = forAllShrinkBlind @Property gen shr $ \case+ SLimited p -> counterexample ("@" ++ show (natVal p)) $+ prop (fromInteger $ natVal p) p++forLimit+ :: forall a. (SaneIntegral a, Arbitrary (SLimited a))+ => (forall n. (KnownIntegral a n, Limited a n)+ => (forall i. Num i => i) -> Proxy n -> Property)+ -> Property+forLimit = forLimit' @a arbitrary shrink+++forPositiveLimit+ :: forall a. (SaneIntegral a, Arbitrary (SLimited a))+ => (forall n. (KnownIntegral a n, Limited a n)+ => (forall i. Num i => i) -> Proxy n -> Property)+ -> Property+forPositiveLimit = forLimit' @a+ (arbitrary `suchThat` isPositive)+ (filter isPositive . shrink)+ where+ isPositive :: SLimited a -> Bool+ isPositive (SLimited p) = natVal p > 0++forSmallLimit+ :: forall a. (SaneIntegral a, Arbitrary (SmallLimited a))+ => (forall n. (KnownIntegral a n, Limited a n)+ => (forall i. Num i => i) -> Proxy n -> Property)+ -> Property+forSmallLimit = forLimit' @a+ (getSmallLimited <$> arbitrary)+ (map getSmallLimited . shrink . SmallLimited)++unsafeWithKnownIntegral+ :: forall n a. (SaneIntegral a, Typeable a)+ => Integer -> ((KnownNat n, Limited a n) => Property) -> Property+unsafeWithKnownIntegral n prop+ | Just (Refl :: a :~: Integer) <- cast (Refl @a)+ , Just (SLimited (_ :: Proxy n')) <- mkUnlimited @a n+ , Refl <- unsafeCoerce Refl :: n :~: n'+ = prop+ | Just (Refl :: a :~: Natural) <- cast (Refl @a)+ , Just (SLimited (_ :: Proxy n')) <- mkUnlimited @a n+ , Refl <- unsafeCoerce Refl :: n :~: n'+ = prop+ | Just (Refl :: a :~: Word) <- cast (Refl @a)+ , Just (SLimited (_ :: Proxy n')) <- mkLimited @a n+ , Refl <- unsafeCoerce Refl :: n :~: n'+ = prop+ | Just (Refl :: a :~: Int) <- cast (Refl @a)+ , Just (SLimited (_ :: Proxy n')) <- mkLimited @a n+ , Refl <- unsafeCoerce Refl :: n :~: n'+ = prop+ | otherwise = discard++newtype IneqCond (n :: Nat) (m :: Nat) = IneqCond ((n <= m) => Property)+unsafeWithInequality+ :: forall (n :: Nat) (m :: Nat). ((n <= m) => Property) -> Property+unsafeWithInequality prop =+ case unsafeCoerce (IneqCond @n @m $ property prop) :: IneqCond 0 1 of+ IneqCond prop' -> prop'++prop_isvalid_under = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \_ (_ :: Proxy n) ->+ property $ \x ->+ x < 0 ==> not $ isValidFinite @n @a (Finite x)+prop_isvalid_over = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ property $ \x ->+ not (x >= n) .||. not (isValidFinite @n @a (Finite x))++prop_valid_finite = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \_ (_ :: Proxy n) ->+ property $ \x -> ioProperty $+ evaluate (isValidFinite $ finite @n @a x)+ `catch` \(_ :: ErrorCall) -> pure True+prop_getFinite_finite = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \_ (_ :: Proxy n) ->+ property $ \x -> ioProperty $+ evaluate (getFinite (finite @n @a x) == x)+ `catch` \(_ :: ErrorCall) -> pure True+prop_finite_getFinite = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ finite (getFinite x) === x++prop_valid_maxBound = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ n > 0 ==> isValidFinite (maxBound @(Finite a n))+prop_maxBound_max = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ n > 0 ==> maxBound >= x++prop_valid_minBound = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ n > 0 ==> isValidFinite (minBound @(Finite a n))+prop_minBound_min = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ n > 0 ==> minBound <= x++prop_valid_toEnum = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \_ (_ :: Proxy n) ->+ property $ \x -> ioProperty $+ evaluate (isValidFinite $ toEnum @(Finite a n) x)+ `catch` \(_ :: ErrorCall) -> pure True+prop_fromEnum_toEnum = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \_ (_ :: Proxy n) ->+ property $ \x -> ioProperty $+ evaluate (fromEnum (toEnum @(Finite a n) x) == x)+ `catch` \(_ :: ErrorCall) -> pure True+prop_toEnum_fromEnum = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ n <= toInteger (maxBound @Int) ==> toEnum (fromEnum x) == x++prop_valid_enumFrom = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Big x :: Big a n) ->+ all isValidFinite [x..]+prop_getFinite_enumFrom = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ property $ \(Big x :: Big a n) ->+ map getFinite [x..]+ === takeWhile (isJust . packFinite @n @a) [getFinite x..]++prop_valid_enumFromTo = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Big x :: Big a n) (Big y) ->+ all isValidFinite [x..y]+prop_valid_enumFromTo' = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Small x :: Small a n) (Small y) ->+ all isValidFinite [x..y]+prop_getFinite_enumFromTo = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Big x :: Big a n) (Big y) ->+ map getFinite [x..y] === [getFinite x..getFinite y]+prop_getFinite_enumFromTo' = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Small x :: Small a n) (Small y) ->+ map getFinite [x..y] === [getFinite x..getFinite y]++prop_valid_enumFromThen = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Big x :: Big a n) (Big y) ->+ x < y ==> all isValidFinite [x,y..]+prop_valid_enumFromThen' = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Small x :: Small a n) (Small y) ->+ x > y ==> all isValidFinite [x,y..]+prop_getFinite_enumFromThen = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Big x :: Big a n) (Big y) ->+ x < y ==> map getFinite [x,y..]+ === takeWhile (isJust . packFinite @n @a) [getFinite x,getFinite y..]+prop_getFinite_enumFromThen' = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Small x :: Small a n) (Small y) ->+ x > y ==> map getFinite [x,y..]+ === takeWhile (isJust . packFinite @n @a) [getFinite x,getFinite y..]++prop_valid_enumFromThenTo = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Small x :: Small a n) (Small y) (Small z) ->+ x /= y ==> all isValidFinite [x,y..z]+prop_getFinite_enumFromThenTo = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Small x :: Small a n) (Small y) (Small z) ->+ x /= y ==> map getFinite [x,y..z] === [getFinite x,getFinite y..getFinite z]++prop_nonint_succ = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Big x :: Big a n) ->+ case packFinite @n @a $ succ $ getFinite x of+ Nothing -> discard+ Just y -> y === succ x++prop_valid_read = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ forPositiveLimit @a $ \_ (_ :: Proxy m) ->+ property $ \(Edgy x :: Edgy a n) -> ioProperty $+ evaluate (isValidFinite $ read @(Finite a m) (show x))+ `catch` \(_ :: ErrorCall) -> pure True+prop_read_show = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ read (show x) === x++prop_valid_plus = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y) ->+ isValidFinite $ x + y+prop_getFinite_plus = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y) ->+ (getFinite x + getFinite y - getFinite (x + y)) `mod` n === 0++prop_valid_minus = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y) ->+ isValidFinite $ x - y+prop_getFinite_minus = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y) ->+ (getFinite x + n - getFinite y - getFinite (x - y)) `mod` n === 0++prop_valid_times = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y) ->+ isValidFinite $ x * y+prop_getFinite_times = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y) ->+ (toInteger (getFinite x) * toInteger (getFinite y)+ - toInteger (getFinite $ x * y)) `mod` n === 0++prop_valid_negate = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ isValidFinite $ -x+prop_getFinite_negate = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ (n - getFinite x - getFinite (-x)) `mod` n === 0++prop_valid_abs = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ isValidFinite $ abs x+prop_getFinite_abs = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ getFinite (abs x) === abs (getFinite x)++prop_valid_signum = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ isValidFinite $ signum x+prop_getFinite_signum = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ getFinite (signum x) === signum (getFinite x)++prop_valid_fromInteger = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \x -> ioProperty $+ evaluate (isValidFinite $ fromInteger @(Finite a n) x)+ `catch` \(_ :: ErrorCall) -> pure True+prop_toInteger_fromInteger = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \_ (_ :: Proxy n) ->+ property $ \x -> ioProperty $+ evaluate (toInteger (fromInteger @(Finite a n) x) == x)+ `catch` \(_ :: ErrorCall) -> pure True+prop_fromInteger_toInteger = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ fromInteger (toInteger x) === x++prop_valid_quot = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y) ->+ y /= 0 ==> isValidFinite $ x `quot` y+prop_getFinite_quot = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y) ->+ y /= 0 ==> getFinite (x `quot` y) === getFinite x `quot` getFinite y++prop_valid_rem = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y) ->+ y /= 0 ==> isValidFinite $ x `rem` y+prop_getFinite_rem = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y) ->+ y /= 0 ==> getFinite (x `rem` y) === getFinite x `rem` getFinite y++prop_valid_div = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y) ->+ y /= 0 ==> isValidFinite $ x `div` y+prop_getFinite_div = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y) ->+ y /= 0 ==> getFinite (x `div` y) === getFinite x `div` getFinite y++prop_valid_mod = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y) ->+ y /= 0 ==> isValidFinite $ x `mod` y+prop_getFinite_mod = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y) ->+ y /= 0 ==> getFinite (x `mod` y) === getFinite x `mod` getFinite y++prop_force = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \_ (_ :: Proxy n) ->+ ioProperty $+ evaluate (rnf @(Finite a n) (error "Expected exception") `seq` False)+ `catch` (\(_ :: ErrorCall) -> pure True)++prop_valid_packFinite = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \_ (_ :: Proxy n) ->+ property $ \x ->+ maybe True isValidFinite $ packFinite @n @a x+prop_getFinite_packFinite = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \_ (_ :: Proxy n) ->+ property $ \x ->+ maybe (property True) ((x ===) . getFinite) $ packFinite @n @a x+prop_finite_packFinite = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \_ (_ :: Proxy n) ->+ property $ \x -> ioProperty $+ case packFinite @n @a x of+ Nothing -> (evaluate (finite @n @a x) >> pure False)+ `catch` \(_ :: ErrorCall) -> pure True+ Just y -> evaluate (y == finite x)++prop_valid_finites = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \_ (_ :: Proxy n) ->+ property $+ all isValidFinite $ finites @n @a+prop_finites_minMax = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ n > 0 ==> minBound `elem` finites @n @a .&&. maxBound `elem` finites @n @a+prop_finites_ordered = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \_ (_ :: Proxy n) ->+ finites @n @a === sort finites+prop_finites_all = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \_ (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ x -- could be discard+ `seq` x `elem` finites @n @a++prop_valid_modulo = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ property $ \x ->+ isValidFinite $ modulo @n @a x+prop_getFinite_modulo = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ property $ \x ->+ (toInteger x - toInteger (getFinite $ modulo @n @a x)) `mod` n === 0++prop_getFinite_equals = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ forPositiveLimit @a $ \_ (_ :: Proxy m) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y :: Edgy a m) ->+ (x `equals` y) === (getFinite x == getFinite y)++prop_getFinite_cmp = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ forPositiveLimit @a $ \_ (_ :: Proxy m) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y :: Edgy a m) ->+ (x `cmp` y) === (getFinite x `compare` getFinite y)++prop_valid_natToFinite = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forPositiveLimit @a $ \m (_ :: Proxy m) ->+ n + 1 <= m ==> unsafeWithInequality @(n + 1) @m $+ property $+ isValidFinite $ natToFinite @n @m @a Proxy+prop_getFinite_natToFinite = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forPositiveLimit @a $ \m (_ :: Proxy m) ->+ n + 1 <= m ==> unsafeWithInequality @(n + 1) @m $+ getFinite (natToFinite @n @m @a Proxy) === n++prop_valid_weaken = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ unsafeWithKnownIntegral @(n + 1) @a (n + 1) $+ property $ \(Edgy x :: Edgy a n) ->+ isValidFinite $ weaken x+prop_finites_weaken = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ unsafeWithKnownIntegral @(n + 1) @a (n + 1) $+ map (weaken @n @a) finites === init finites++prop_valid_strengthen = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ unsafeWithKnownIntegral @(n + 1) @a (n + 1) $+ property $ \(Edgy x :: Edgy a (n + 1)) ->+ maybe True isValidFinite $ strengthen x+prop_finites_strengthen = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ unsafeWithKnownIntegral @(n + 1) @a (n + 1) $+ map (strengthen @n @a) finites === map Just finites ++ [Nothing]++prop_valid_shift = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ unsafeWithKnownIntegral @(n + 1) @a (n + 1) $+ property $ \(Edgy x :: Edgy a n) ->+ isValidFinite $ shift x+prop_finites_shift = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ unsafeWithKnownIntegral @(n + 1) @a (n + 1) $+ map (shift @n @a) finites === drop 1 finites++prop_valid_unshift = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ unsafeWithKnownIntegral @(n + 1) @a (n + 1) $+ property $ \(Edgy x :: Edgy a (n + 1)) ->+ maybe True isValidFinite $ unshift x+prop_finites_unshift = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ unsafeWithKnownIntegral @(n + 1) @a (n + 1) $+ map (unshift @n @a) finites === [Nothing] ++ map Just finites++prop_valid_weakenN = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ forPositiveLimit @a $ \m (_ :: Proxy m) ->+ n <= m ==> unsafeWithInequality @n @m $+ property $ \(Edgy x :: Edgy a n) ->+ isValidFinite $ weakenN @n @m @a x+prop_finites_weakenN = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \m (_ :: Proxy m) ->+ n <= m ==> unsafeWithInequality @n @m $+ map (weakenN @n @m @a) finites === take n finites++prop_valid_strengthenN = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ forLimit @a $ \_ (_ :: Proxy m) ->+ property $ \(Edgy x :: Edgy a n) ->+ maybe True isValidFinite $ strengthenN @n @m x+prop_finites_strengthenN = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \m (_ :: Proxy m) ->+ map (strengthenN @n @m @a) finites+ === take n (map Just finites) ++ replicate (n - m) Nothing++prop_valid_shiftN = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ forPositiveLimit @a $ \m (_ :: Proxy m) ->+ n <= m ==> unsafeWithInequality @n @m $+ property $ \(Edgy x :: Edgy a n) ->+ isValidFinite $ shiftN @n @m @a x+prop_finites_shiftN = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \m (_ :: Proxy m) ->+ n <= m ==> unsafeWithInequality @n @m $+ map (shiftN @n @m @a) finites === drop (m - n) finites++prop_valid_unshiftN = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ forLimit @a $ \_ (_ :: Proxy m) ->+ property $ \(Edgy x :: Edgy a n) ->+ maybe True isValidFinite $ unshiftN @n @m x+prop_finites_unshiftN = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \m (_ :: Proxy m) ->+ map (unshiftN @n @m @a) finites+ === replicate (n - m) Nothing ++ drop (m - n) (map Just finites)++prop_valid_weakenProxy = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \k (_ :: Proxy k) ->+ unsafeWithKnownIntegral @(n + k) @a (n + k) $+ property $ \(Edgy x :: Edgy a n) ->+ isValidFinite $ weakenProxy @n @k Proxy x+prop_finites_weakenProxy = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \k (_ :: Proxy k) ->+ unsafeWithKnownIntegral @(n + k) @a (n + k) $+ map (weakenProxy @n @k @a Proxy) finites === take n finites++prop_valid_strengthenProxy = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \k (_ :: Proxy k) ->+ unsafeWithKnownIntegral @(n + k) @a (n + k) $+ property $ \(Edgy x :: Edgy a (n + k)) ->+ maybe True isValidFinite $ strengthenProxy @n @k Proxy x+prop_finites_strengthenProxy = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \k (_ :: Proxy k) ->+ unsafeWithKnownIntegral @(n + k) @a (n + k) $+ map (strengthenProxy @n @k @a Proxy) finites+ === take n (map Just finites) ++ replicate k Nothing++prop_valid_shiftProxy = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \k (_ :: Proxy k) ->+ unsafeWithKnownIntegral @(n + k) @a (n + k) $+ property $ \(Edgy x :: Edgy a n) ->+ isValidFinite $ shiftProxy @n @k Proxy x+prop_finites_shiftProxy = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \k (_ :: Proxy k) ->+ unsafeWithKnownIntegral @(n + k) @a (n + k) $+ map (shiftProxy @n @k @a Proxy) finites === drop k finites++prop_valid_unshiftProxy = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \k (_ :: Proxy k) ->+ unsafeWithKnownIntegral @(n + k) @a (n + k) $+ property $ \(Edgy x :: Edgy a (n + k)) ->+ maybe True isValidFinite $ unshiftProxy @n @k Proxy x+prop_finites_unshiftProxy = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \k (_ :: Proxy k) ->+ unsafeWithKnownIntegral @(n + k) @a (n + k) $+ map (unshiftProxy @n @k @a Proxy) finites+ === replicate k Nothing ++ map Just finites++prop_strengthen_weaken = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ unsafeWithKnownIntegral @(n + 1) @a (n + 1) $+ strengthen (weaken x) === Just x+prop_weaken_strengthen = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ unsafeWithKnownIntegral @(n + 1) @a (n + 1) $+ property $ \(Edgy x :: Edgy a (n + 1)) ->+ maybe True (== x) (weaken <$> strengthen x)++prop_unshift_shift = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ property $ \(Edgy x :: Edgy a n) ->+ unsafeWithKnownIntegral @(n + 1) @a (n + 1) $+ unshift (shift x) === Just x+prop_shift_unshift = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ unsafeWithKnownIntegral @(n + 1) @a (n + 1) $+ property $ \(Edgy x :: Edgy a (n + 1)) ->+ maybe True (== x) (shift <$> unshift x)++prop_strengthenN_weakenN = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ forPositiveLimit @a $ \m (_ :: Proxy m) ->+ n <= m ==> unsafeWithInequality @n @m $+ property $ \(Edgy x :: Edgy a n) ->+ strengthenN (weakenN @n @m x) === Just x+prop_weakenN_strengthenN = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \m (_ :: Proxy m) ->+ m <= n ==> unsafeWithInequality @m @n $+ property $ \(Edgy x :: Edgy a n) ->+ maybe True (== x) (weakenN <$> strengthenN @n @m x)++prop_unshiftN_shiftN = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ forPositiveLimit @a $ \m (_ :: Proxy m) ->+ n <= m ==> unsafeWithInequality @n @m $+ property $ \(Edgy x :: Edgy a n) ->+ unshiftN (shiftN @n @m x) === Just x+prop_shiftN_unshiftN = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \m (_ :: Proxy m) ->+ m <= n ==> unsafeWithInequality @m @n $+ property $ \(Edgy x :: Edgy a n) ->+ maybe True (== x) (shiftN <$> unshiftN @n @m x)++prop_strengthenProxy_weakenProxy = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \k (_ :: Proxy k) ->+ property $ \(Edgy x :: Edgy a n) ->+ unsafeWithKnownIntegral @(n + k) @a (n + k) $+ strengthenProxy Proxy (weakenProxy @n @k Proxy x) === Just x+prop_weakenProxy_strengthenProxy = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \k (_ :: Proxy k) ->+ unsafeWithKnownIntegral @(n + k) @a (n + k) $+ property $ \(Edgy x :: Edgy a (n + k)) ->+ maybe True (== x) (weakenProxy Proxy <$> strengthenProxy @n @k Proxy x)++prop_unshiftProxy_shiftProxy = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \k (_ :: Proxy k) ->+ property $ \(Edgy x :: Edgy a n) ->+ unsafeWithKnownIntegral @(n + k) @a (n + k) $+ unshiftProxy Proxy (shiftProxy @n @k Proxy x) === Just x+prop_shiftProxy_unshiftProxy = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \k (_ :: Proxy k) ->+ unsafeWithKnownIntegral @(n + k) @a (n + k) $+ property $ \(Edgy x :: Edgy a (n + k)) ->+ maybe True (== x) (shiftProxy Proxy <$> unshiftProxy @n @k Proxy x)++prop_valid_add = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ forPositiveLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n + m) @a (n + m) $+ property $ \(Edgy x :: Edgy a n) (Edgy y :: Edgy a m) ->+ isValidFinite $ add x y+prop_getFinite_add = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ forPositiveLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n + m) @a (n + m) $+ property $ \(Edgy x :: Edgy a n) (Edgy y :: Edgy a m) ->+ getFinite (add x y) === getFinite x + getFinite y++prop_valid_sub = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ forPositiveLimit @a $ \_ (_ :: Proxy m) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y :: Edgy a m) ->+ either isValidFinite isValidFinite $ sub x y+prop_getFinite_sub = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ forPositiveLimit @a $ \_ (_ :: Proxy m) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y :: Edgy a m) ->+ either (negate . toInteger . getFinite) (toInteger . getFinite) (sub x y)+ === toInteger (getFinite x) - toInteger (getFinite y)+prop_sub_Left_0 = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \_ (_ :: Proxy n) ->+ forPositiveLimit @a $ \_ (_ :: Proxy m) ->+ property $ \(Edgy x :: Edgy a n) (Edgy y :: Edgy a m) ->+ sub x y =/= Left 0++prop_valid_multiply = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ forPositiveLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n GHC.TypeLits.* m) @a (n * m) $+ property $ \(Edgy x :: Edgy a n) (Edgy y :: Edgy a m) ->+ isValidFinite $ multiply x y+prop_getFinite_multiply = forType $ \(_ :: Proxy a) ->+ forPositiveLimit @a $ \n (_ :: Proxy n) ->+ forPositiveLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n GHC.TypeLits.* m) @a (n * m) $+ property $ \(Edgy x :: Edgy a n) (Edgy y :: Edgy a m) ->+ getFinite (multiply x y) === getFinite x * getFinite y++prop_valid_combineSum = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n + m) @a (n + m) $+ property $ \e ->+ isValidFinite $ combineSum+ $ bimap (\(Edgy x :: Edgy a n) -> x) (\(Edgy y :: Edgy a m) -> y) e+prop_finites_combineSum = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n + m) @a (n + m) $+ map (combineSum @n @m @a) (map Left finites ++ map Right finites)+ === finites++prop_valid_combineZero = forType $ \(_ :: Proxy a) ->+ unsafeWithKnownIntegral @0 @a 0 $+ ioProperty $ evaluate (isValidFinite $ combineZero @a $ error "test")+ `catch` \(ErrorCall msg) -> pure (msg == "test")+prop_finites_combineZero = forType $ \(_ :: Proxy a) ->+ unsafeWithKnownIntegral @0 @a 0 $+ map (combineZero @a) [] === finites++prop_valid_combineProduct = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n GHC.TypeLits.* m) @a (n * m) $+ property $ \p ->+ isValidFinite $ combineProduct+ $ bimap (\(Edgy x :: Edgy a n) -> x) (\(Edgy y :: Edgy a m) -> y) p+prop_finites_combineProduct = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n GHC.TypeLits.* m) @a (n * m) $+ map (combineProduct @n @m @a) [(x, y) | y <- finites, x <- finites]+ === finites++prop_valid_combineOne = forType $ \(_ :: Proxy a) ->+ unsafeWithKnownIntegral @1 @a 1 $+ property $ isValidFinite $ combineOne @a ()+prop_finites_combineOne = forType $ \(_ :: Proxy a) ->+ unsafeWithKnownIntegral @1 @a 1 $+ property $ [combineOne @a ()] === finites++prop_valid_combineExponential = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(m ^ n) @a (m ^ n) $+ property $ \(Blind (f :: Big a n -> Big a m)) ->+ isValidFinite $ combineExponential (\x -> case f (Big x) of Big y -> y)+prop_finites_combineExponential = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \m (_ :: Proxy m) ->+ if m ^ n > 2000000 then property () else+ m ^ n <= 10000 ==>+ unsafeWithKnownIntegral @(m ^ n) @a (m ^ n) $+ property $+ [ combineExponential ((xs !!) . fromIntegral . getFinite @n @a)+ | xs <- reverse <$> replicateM n (finites @m)+ ] === finites++prop_valid_separateSum = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n + m) @a (n + m) $+ property $ \(Edgy x :: Edgy a (n + m)) ->+ either isValidFinite isValidFinite $ separateSum @n @m x+prop_finites_separateSum = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n + m) @a (n + m) $+ map (separateSum @n @m @a) finites === map Left finites ++ map Right finites++prop_seq_separateZero = forType $ \(_ :: Proxy a) ->+ unsafeWithKnownIntegral @0 @a 0 $+ ioProperty $ evaluate (absurd $ separateZero @a $ error "test")+ `catch` \(ErrorCall msg) -> pure (msg == "test")+prop_finites_separateZero = forType $ \(_ :: Proxy a) ->+ unsafeWithKnownIntegral @0 @a 0 $+ map (separateZero @a) finites === []++prop_valid_separateProduct = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n GHC.TypeLits.* m) @a (n * m) $+ property $ \(Edgy x :: Edgy a (n GHC.TypeLits.* m)) ->+ x -- could be discard+ `seq` isValidFinite (fst $ separateProduct @n @m x)+ .&&. isValidFinite (snd $ separateProduct @n @m x)+prop_finites_separateProduct = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n GHC.TypeLits.* m) @a (n * m) $+ map (separateProduct @n @m @a) finites+ === [(x, y) | y <- finites, x <- finites]++prop_finites_separateOne = forType $ \(_ :: Proxy a) ->+ unsafeWithKnownIntegral @1 @a 1 $+ map (separateOne @a) finites === [()]++prop_valid_separateExponential = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(m ^ n) @a (m ^ n) $+ property $ \(Big f :: Big a (m ^ n)) (Big x :: Big a n) ->+ f `seq` x -- could be discard+ `seq` isValidFinite (separateExponential @n @m @a f x)+prop_finites_separateExponential = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \m (_ :: Proxy m) ->+ if m ^ n > 2000000 then property () else+ m ^ n <= 10000 ==>+ unsafeWithKnownIntegral @(m ^ n) @a (m ^ n) $+ map (<$> finites) (map (separateExponential @n @m @a) finites)+ === [reverse xs | xs <- replicateM n finites]++prop_combineSum_separateSum = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n + m) @a (n + m) $+ property $ \(Edgy x :: Edgy a (n + m)) ->+ combineSum (separateSum @n @m x) === x+prop_separateSum_combineSum = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n + m) @a (n + m) $+ property $ \e ->+ let x = bimap (\(Edgy x :: Edgy a n) -> x) (\(Edgy y :: Edgy a m) -> y) e in+ separateSum (combineSum x) === x++prop_combineProduct_separateProduct = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n GHC.TypeLits.* m) @a (n * m) $+ property $ \(Edgy x :: Edgy a (n GHC.TypeLits.* m)) ->+ x -- could be discard+ `seq` combineProduct (separateProduct @n @m x) === x+prop_separateProduct_combineProduct = forType $ \(_ :: Proxy a) ->+ forLimit @a $ \n (_ :: Proxy n) ->+ forLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(n GHC.TypeLits.* m) @a (n * m) $+ property $ \p ->+ let x = bimap (\(Edgy x :: Edgy a n) -> x) (\(Edgy y :: Edgy a m) -> y) p in+ force x -- could be discard+ `seq` separateProduct (combineProduct x) === x++prop_combineOne_separateOne = forType $ \(_ :: Proxy a) ->+ unsafeWithKnownIntegral @1 @a 1 $+ property $ \(Big x :: Big a 1) ->+ combineOne (separateOne @a x) === x+prop_separateOne_combineOne = forType $ \(_ :: Proxy a) ->+ unsafeWithKnownIntegral @1 @a 1 $+ property $ \x ->+ separateOne (combineOne @a x) === x++prop_separateExponential_combineExponential = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(m ^ n) @a (m ^ n) $+ property $ \(Blind (f :: Big a n -> Big a m)) ->+ let f' x = case f (Big x) of Big y -> y in+ force (f' <$> listToMaybe finites) -- could be discard+ `seq` (separateExponential @n @m @a (combineExponential f') <$> finites)+ === (f' <$> finites)+prop_combineExponential_separateExponential = forType $ \(_ :: Proxy a) ->+ forSmallLimit @a $ \n (_ :: Proxy n) ->+ forSmallLimit @a $ \m (_ :: Proxy m) ->+ unsafeWithKnownIntegral @(m ^ n) @a (m ^ n) $+ property $ \(Big f :: Big a (m ^ n)) ->+ f `seq` -- could be discard+ combineExponential (separateExponential @n @m @a f) === f return [] main = $quickCheckAll >>= \case