integer-types 0.0.0.0 → 0.0.0.1
raw patch · 32 files changed
+1268/−1388 lines, 32 filesdep +hspec-hedgehogdep +quaaludedep ~hedgehogdep ~hspecPVP ok
version bump matches the API change (PVP)
Dependencies added: hspec-hedgehog, quaalude
Dependency ranges changed: hedgehog, hspec
API changes (from Hackage documentation)
Files
- changelog.md +7/−1
- integer-generators/Integer/Gen.hs +0/−122
- integer-types.cabal +19/−57
- integer-types/Integer.hs +0/−24
- integer-types/Integer/BoundedBelow.hs +0/−11
- integer-types/Integer/Conversion.hs +0/−93
- integer-types/Integer/Finite.hs +0/−59
- integer-types/Integer/Integer.hs +0/−65
- integer-types/Integer/Natural.hs +0/−86
- integer-types/Integer/Positive.hs +0/−75
- integer-types/Integer/Positive/Unsafe.hs +0/−160
- integer-types/Integer/Sign.hs +0/−24
- integer-types/Integer/Signed.hs +0/−213
- integer-types/Integer/Subtraction.hs +0/−47
- library/Integer.hs +22/−0
- library/Integer/BoundedBelow.hs +11/−0
- library/Integer/Conversion.hs +91/−0
- library/Integer/Finite.hs +59/−0
- library/Integer/Integer.hs +64/−0
- library/Integer/Natural.hs +84/−0
- library/Integer/Positive.hs +73/−0
- library/Integer/Positive/Unsafe.hs +159/−0
- library/Integer/Sign.hs +24/−0
- library/Integer/Signed.hs +211/−0
- library/Integer/Subtraction.hs +47/−0
- test-integer-arithmetic/Main.hs +0/−78
- test-integer-conversions/Main.hs +0/−91
- test-integer-deepseq/Main.hs +0/−40
- test-integer-enum/Main.hs +0/−71
- test-integer-finite/Main.hs +0/−71
- test/Integer/Gen.hs +120/−0
- test/Main.hs +277/−0
changelog.md view
@@ -1,3 +1,9 @@+# 0.0.0.1++Consolidate all the test suites into one++Remove `Safe` pragmas+ # 0.0.0.0 (2022-11-29) -* Initial release+Initial release
− integer-generators/Integer/Gen.hs
@@ -1,122 +0,0 @@-module Integer.Gen- (- GenIntegral (integral),- GenFinite (finite),- astronomical,- )- where--import Control.Applicative (pure, (<*>))-import Data.Function (id, ($))-import Data.Functor (fmap)-import Data.Int (Int)-import Data.Word (Word)-import Integer (BoundedBelow (..), Integer, Natural, Positive, Sign (..),- Signed (..))-import Text.Show (Show)--import qualified Hedgehog-import qualified Hedgehog.Gen as Gen-import qualified Hedgehog.Range as Range-import qualified Prelude as Bounded (Bounded (..))-import qualified Prelude as Num (Integral (..), Num (..), (+), (^))-------class (Num.Integral a, Show a) => GenIntegral a- where- -- | Generators for 'Integer', 'Natural', 'Positive',- -- or 'Signed' selected from one of three methods:- --- -- * small numbers (magnitude less than ten)- -- * large numbers (well in excess of 64-bit)- -- * numbers at or around a bound of 'Int' or 'Word'- integral :: Hedgehog.Gen a--instance GenIntegral Integer where integral = integer-instance GenIntegral Natural where integral = boundedBelow-instance GenIntegral Positive where integral = boundedBelow-instance GenIntegral Signed where integral = signed-------class (Num.Integral a, Bounded.Bounded a, Show a) => GenFinite a- where- finite :: Hedgehog.Gen a--instance GenFinite Int where finite = defaultFinite--instance GenFinite Word where finite = defaultFinite--defaultFinite :: (Num.Integral a, Bounded.Bounded a) => Hedgehog.Gen a-defaultFinite = Gen.choice- [ Gen.integral $ Range.linear Bounded.minBound Bounded.maxBound- , Gen.integral $ Range.linear Bounded.maxBound Bounded.minBound- ]-------smol :: Num.Integral a => a-smol = 10--astronomical :: Num.Integral a => a-astronomical = 2 Num.^ (99 :: Integer)--bigRange :: Num.Integral a => Range.Range a-bigRange = Range.exponential smol astronomical-------integer :: Hedgehog.Gen Integer-integer = Gen.choice [smolInteger, nearFiniteBoundInteger, bigInteger]--smolInteger :: Hedgehog.Gen Integer-smolInteger = Gen.integral $ Range.linearFrom 0 (Num.negate smol) smol--bigInteger :: Hedgehog.Gen Integer-bigInteger = Gen.element [id, Num.negate] <*> Gen.integral bigRange--nearFiniteBoundInteger :: Hedgehog.Gen Integer-nearFiniteBoundInteger = Gen.element [id, Num.negate] <*> nearPositiveFiniteBound-------boundedBelow :: forall a. (BoundedBelow a, Num.Integral a) => Hedgehog.Gen a-boundedBelow = Gen.choice [smolBoundedBelow, nearPositiveFiniteBound, bigBoundedBelow]--smolBoundedBelow :: forall a. (BoundedBelow a, Num.Integral a) => Hedgehog.Gen a-smolBoundedBelow = fmap Num.fromInteger $ Gen.integral $ Range.linear (Num.toInteger $ minBound @a) smol--bigBoundedBelow :: forall a. (BoundedBelow a, Num.Integral a) => Hedgehog.Gen a-bigBoundedBelow = fmap Num.fromInteger $ Gen.integral bigRange--nearPositiveFiniteBound :: forall a. Num.Integral a => Hedgehog.Gen a-nearPositiveFiniteBound = fmap Num.fromInteger $- pure (Num.+)- <*> Gen.element- [ Num.toInteger (Bounded.maxBound :: Int)- , Num.toInteger (Bounded.maxBound :: Word)- ]- <*> smolInteger-------signed :: Hedgehog.Gen Signed-signed = Gen.choice [smolSigned, nearFiniteBoundSigned, bigSigned]--smolSigned :: Hedgehog.Gen Signed-smolSigned = Gen.frequency- [ (,) 1 $ pure Zero- , (,) 9 $ pure NonZero <*> sign <*> smolBoundedBelow- ]--bigSigned :: Hedgehog.Gen Signed-bigSigned = pure NonZero <*> sign <*> bigBoundedBelow--nearFiniteBoundSigned :: Hedgehog.Gen Signed-nearFiniteBoundSigned = pure NonZero <*> sign <*> nearPositiveFiniteBound-------sign :: Hedgehog.Gen Sign-sign = Gen.element [PlusSign, MinusSign]
integer-types.cabal view
@@ -1,7 +1,7 @@ cabal-version: 3.0 name: integer-types-version: 0.0.0.0+version: 0.0.0.1 category: Numeric synopsis: Integer, Natural, and Positive@@ -20,7 +20,7 @@ license: Apache-2.0 license-file: license.txt -extra-doc-files: readme.md changelog.md+extra-source-files: *.md common base default-language: GHC2021@@ -32,30 +32,13 @@ PatternSynonyms ViewPatterns build-depends:- base ^>= 4.16 || ^>= 4.17+ , base ^>= 4.16 || ^>= 4.17 , deepseq ^>= 1.4.6--common test- import: base- default-extensions:- AllowAmbiguousTypes- build-depends:- exceptions- , integer-types--common test-with-hedgehog- import: test- build-depends:- hedgehog ^>= 1.1 || ^>= 1.2--common test-with-hspec- import: test- build-depends:- hspec+ , quaalude ^>= 0.0 library import: base- hs-source-dirs: integer-types+ hs-source-dirs: library exposed-modules: Integer Integer.BoundedBelow@@ -70,40 +53,19 @@ other-modules: Integer.Positive.Unsafe -library integer-generators- import: test-with-hedgehog- hs-source-dirs: integer-generators- exposed-modules: Integer.Gen--test-suite test-integer-arithmetic- import: test-with-hedgehog- type: exitcode-stdio-1.0- main-is: Main.hs- hs-source-dirs: test-integer-arithmetic- build-depends: integer-generators--test-suite test-integer-conversions- import: test-with-hedgehog- type: exitcode-stdio-1.0- main-is: Main.hs- hs-source-dirs: test-integer-conversions- build-depends: integer-generators--test-suite test-integer-enum- import: test-with-hspec- type: exitcode-stdio-1.0- main-is: Main.hs- hs-source-dirs: test-integer-enum--test-suite test-integer-deepseq- import: test-with-hspec- type: exitcode-stdio-1.0- main-is: Main.hs- hs-source-dirs: test-integer-deepseq--test-suite test-integer-finite- import: test-with-hedgehog+test-suite test-integer-types+ import: base+ hs-source-dirs: test type: exitcode-stdio-1.0+ default-extensions:+ AllowAmbiguousTypes+ BlockArguments+ build-depends:+ , exceptions ^>= 0.10.4+ , integer-types+ , hedgehog ^>= 1.0.5 || ^>= 1.1 || ^>= 1.2+ , hspec ^>= 2.8.5 || ^>= 2.9 || ^>= 2.10+ , hspec-hedgehog ^>= 0.0.1 main-is: Main.hs- hs-source-dirs: test-integer-finite- build-depends: integer-generators+ other-modules:+ Integer.Gen
− integer-types/Integer.hs
@@ -1,24 +0,0 @@-{-# language Safe #-}--module Integer- (- {- ** Types -} Integer, Natural, Positive,- Signed (Zero, NonZero, Minus, Plus), Sign (MinusSign, PlusSign),- {- ** Subtraction -} Subtraction (subtractInteger, subtractSigned), Subtraction' (subtract),- {- ** Conversion -} IntegerNarrow (narrow), IntegerConvert (convert), IntegerEquiv, yolo, ConvertWithFinite (toInt, fromInt, toWord, fromWord), Finite (..),- {- ** Lower bound -} BoundedBelow (minBound),- )- where--import Integer.BoundedBelow (BoundedBelow (minBound))-import Integer.Conversion (IntegerConvert (convert), IntegerEquiv,- IntegerNarrow (narrow), yolo)-import Integer.Finite (ConvertWithFinite (fromInt, fromWord, toInt, toWord),- Finite (..))-import Integer.Integer (Integer)-import Integer.Natural (Natural)-import Integer.Positive (Positive)-import Integer.Sign (Sign (MinusSign, PlusSign))-import Integer.Signed (Signed (Minus, NonZero, Plus, Zero))-import Integer.Subtraction (Subtraction (subtractInteger, subtractSigned),- Subtraction' (subtract))
− integer-types/Integer/BoundedBelow.hs
@@ -1,11 +0,0 @@-module Integer.BoundedBelow where--import Numeric.Natural (Natural)--class BoundedBelow a where- minBound :: a--instance BoundedBelow Natural where- minBound = 0--
− integer-types/Integer/Conversion.hs
@@ -1,93 +0,0 @@-{-# language Safe #-}--module Integer.Conversion- (- IntegerNarrow (narrow),- IntegerConvert (convert),- IntegerEquiv,- yolo,- )- where--import Data.Function (id, (.))-import Data.Maybe (Maybe (..))-import Integer.Integer (Integer)-import Integer.Natural (Natural)-import Integer.Positive (Positive)-import Integer.Signed (Signed)--import qualified Integer.Integer as Integer-import qualified Integer.Natural as Natural-import qualified Integer.Positive as Positive-import qualified Integer.Signed as Signed-import qualified Prelude as Num (Integral (..), Num (..))--class IntegerNarrow a b => IntegerConvert a b where- convert :: a -> b--class IntegerNarrow a b where- narrow :: a -> Maybe b--class (IntegerConvert a b, IntegerConvert b a) => IntegerEquiv a b------ Isomorphisms -----instance IntegerEquiv Integer Integer-instance IntegerConvert Integer Integer where convert = id-instance IntegerNarrow Integer Integer where narrow = Just--instance IntegerEquiv Natural Natural-instance IntegerConvert Natural Natural where convert = id-instance IntegerNarrow Natural Natural where narrow = Just--instance IntegerEquiv Positive Positive-instance IntegerConvert Positive Positive where convert = id-instance IntegerNarrow Positive Positive where narrow = Just--instance IntegerEquiv Signed Signed-instance IntegerConvert Signed Signed where convert = id-instance IntegerNarrow Signed Signed where narrow = Just--instance IntegerEquiv Integer Signed-instance IntegerConvert Integer Signed where convert = Integer.toSigned-instance IntegerNarrow Integer Signed where narrow = Just . convert--instance IntegerEquiv Signed Integer-instance IntegerConvert Signed Integer where convert = Signed.toInteger-instance IntegerNarrow Signed Integer where narrow = Just . convert------ Prisms -----instance IntegerNarrow Integer Natural where narrow = Integer.toNatural-instance IntegerNarrow Natural Integer where narrow = Just . convert-instance IntegerConvert Natural Integer where convert = Natural.toInteger--instance IntegerNarrow Signed Natural where narrow = Signed.toNatural-instance IntegerNarrow Natural Signed where narrow = Just . convert-instance IntegerConvert Natural Signed where convert = Natural.toSigned--instance IntegerNarrow Integer Positive where narrow = Integer.toPositive-instance IntegerNarrow Positive Integer where narrow = Just . convert-instance IntegerConvert Positive Integer where convert = Positive.toInteger--instance IntegerNarrow Natural Positive where narrow = Natural.toPositive-instance IntegerNarrow Positive Natural where narrow = Just . convert-instance IntegerConvert Positive Natural where convert = Positive.toNatural--instance IntegerNarrow Signed Positive where narrow = Signed.toPositive-instance IntegerNarrow Positive Signed where narrow = Just . convert-instance IntegerConvert Positive Signed where convert = Positive.toSigned------ lol ------- | Partial conversion between 'Num.Integral' types via 'Integer'------ @--- yolo = 'Num.fromInteger' . 'Num.toInteger'--- @----yolo :: (Num.Integral a, Num.Num b) => a -> b-yolo = Num.fromInteger . Num.toInteger
− integer-types/Integer/Finite.hs
@@ -1,59 +0,0 @@-module Integer.Finite where--import Data.Function ((.))-import Data.Int (Int)-import Data.Maybe (Maybe)-import Data.Word (Word)-import Integer.Integer (Integer)-import Integer.Natural (Natural)-import Integer.Positive (Positive)-import Integer.Signed (Signed)-import Prelude (Bounded, Integral)--import qualified Data.Maybe as Maybe-import qualified Integer.Integer as Integer-import qualified Integer.Natural as Natural-import qualified Integer.Positive as Positive-import qualified Integer.Signed as Signed--class ConvertWithFinite a where- toWord :: a -> Maybe Word- fromWord :: Word -> Maybe a- toInt :: a -> Maybe Int- fromInt :: Int -> Maybe a--instance ConvertWithFinite Natural where- toWord = Natural.toWord- fromWord = Maybe.Just . Natural.fromWord- toInt = Natural.toInt- fromInt = Natural.fromInt--instance ConvertWithFinite Positive where- toWord = Positive.toWord- fromWord = Positive.fromWord- toInt = Positive.toInt- fromInt = Positive.fromInt--instance ConvertWithFinite Integer where- toWord = Integer.toWord- fromWord = Maybe.Just . Integer.fromWord- toInt = Integer.toInt- fromInt = Maybe.Just . Integer.fromInt--instance ConvertWithFinite Signed where- toWord = Signed.toWord- fromWord = Maybe.Just . Signed.fromWord- toInt = Signed.toInt- fromInt = Maybe.Just . Signed.fromInt--class (Bounded b, Integral b) => Finite b where- toFinite :: ConvertWithFinite a => a -> Maybe b- fromFinite :: ConvertWithFinite a => b -> Maybe a--instance Finite Int where- toFinite = toInt- fromFinite = fromInt--instance Finite Word where- toFinite = toWord- fromFinite = fromWord
− integer-types/Integer/Integer.hs
@@ -1,65 +0,0 @@-{-# language Safe #-}--module Integer.Integer- (- {- * Type -} Integer,- {- * Conversion -}- {- ** Positive -} toPositive, fromPositive,- {- ** Natural -} toNatural, fromNatural,- {- ** Signed -} toSigned, fromSigned,- {- ** Int -} toInt, fromInt,- {- ** Word -} toWord, fromWord,- )- where--import Data.Int (Int)-import Data.Maybe (Maybe (..))-import Data.Word (Word)-import Integer.Positive (Positive)-import Integer.Signed (Signed (..))-import Numeric.Natural (Natural)-import Prelude (Integer)--import qualified Data.Bool as Bool-import qualified Data.Ord as Ord-import qualified Integer.Natural as Natural-import qualified Integer.Positive as Positive-import qualified Integer.Signed as Signed-import qualified Prelude as Bounded (Bounded (..))-import qualified Prelude as Num (Integral (..), Num (..))--toPositive :: Integer -> Maybe Positive-toPositive = Positive.fromInteger--fromPositive :: Positive -> Integer-fromPositive = Positive.toInteger--toNatural :: Integer -> Maybe Natural-toNatural = Natural.fromInteger--fromNatural :: Natural -> Integer-fromNatural = Natural.toInteger--toSigned :: Integer -> Signed-toSigned = Signed.fromInteger--fromSigned :: Signed -> Integer-fromSigned = Signed.toInteger--toInt :: Integer -> Maybe Int-toInt x = if ok then Just (Num.fromInteger x) else Nothing- where- ok = x Ord.>= Num.toInteger (Bounded.minBound :: Int) Bool.&&- x Ord.<= Num.toInteger (Bounded.maxBound :: Int)--fromInt :: Int -> Integer-fromInt = Num.toInteger--toWord :: Integer -> Maybe Word-toWord x = if ok then Just (Num.fromInteger x) else Nothing- where- ok = x Ord.>= Num.toInteger (Bounded.minBound :: Word) Bool.&&- x Ord.<= Num.toInteger (Bounded.maxBound :: Word)--fromWord :: Word -> Integer-fromWord = Num.toInteger
− integer-types/Integer/Natural.hs
@@ -1,86 +0,0 @@-{-# language Trustworthy #-}--module Integer.Natural- (- {- * Type -} Natural,- {- * Subtraction -} subtract,- {- * Conversion -}- {- ** Positive -} toPositive, fromPositive,- {- ** Integer -} toInteger, fromInteger,- {- ** Signed -} toSigned, fromSigned,- {- ** Int -} toInt, fromInt,- {- ** Word -} toWord, fromWord,- {- * One (1) -} one, addOne, subtractOne,- )- where--import Data.Function (($))-import Data.Int (Int)-import Data.Maybe (Maybe (..))-import Data.Word (Word)-import Integer.Signed (Signed (..))-import Numeric.Natural (Natural)-import Prelude (Integer)--import qualified Data.Ord as Ord-import qualified Integer.Positive as Positive-import qualified Integer.Positive.Unsafe as Positive.Unsafe-import qualified Integer.Signed as Signed-import qualified Prelude as Bounded (Bounded (..))-import qualified Prelude as Num (Integral (..), Num (..))--toPositive :: Natural -> Maybe Positive.Unsafe.Positive-toPositive = Positive.fromNatural--fromPositive :: Positive.Unsafe.Positive -> Natural-fromPositive = Positive.toNatural--fromInteger :: Integer -> Maybe Natural-fromInteger x = if x Ord.>= 0 then Just (Num.fromInteger x) else Nothing--toInteger :: Natural -> Integer-toInteger = Num.toInteger--toSigned :: Natural -> Signed-toSigned = Signed.fromNatural--fromSigned :: Signed -> Maybe Natural-fromSigned = Signed.toNatural--toInt :: Natural -> Maybe Int-toInt x = if ok then Just (Num.fromInteger x') else Nothing- where- ok = x' Ord.<= Num.toInteger (Bounded.maxBound :: Int)- x' = Num.toInteger x--fromInt :: Int -> Maybe Natural-fromInt x = if ok then Just (Num.fromInteger x') else Nothing- where- ok = x Ord.>= 0- x' = Num.toInteger x--toWord :: Natural -> Maybe Word-toWord x = if ok then Just (Num.fromInteger x') else Nothing- where- ok = x' Ord.<= Num.toInteger (Bounded.maxBound :: Word)- x' = Num.toInteger x--fromWord :: Word -> Natural-fromWord x = Num.fromInteger (Num.toInteger x)--subtract :: Natural -> Natural -> Signed-subtract a b = case Ord.compare a b of- Ord.EQ -> Zero- Ord.GT -> Plus $ Positive.Unsafe.fromNatural $ (Num.-) a b- Ord.LT -> Minus $ Positive.Unsafe.fromNatural $ (Num.-) b a--one :: Natural-one = 1--addOne :: Integer -> Integer-addOne = (Num.+ 1)--subtractOne :: Natural -> Maybe Signed-subtractOne x = case x of- 0 -> Nothing- p -> Just (subtract p 1)
− integer-types/Integer/Positive.hs
@@ -1,75 +0,0 @@-{-# language Trustworthy #-}--module Integer.Positive- (- {- * Type -} Positive,- {- * Subtraction -} subtract,- {- * Conversion -}- {- ** Natural -} toNatural, fromNatural,- {- ** Integer -} toInteger, fromInteger,- {- ** Signed -} toSigned, fromSigned,- {- ** Int -} toInt, fromInt,- {- ** Word -} toWord, fromWord,- {- * One (1) -} one, addOne, subtractOne,- )- where--import Data.Function (($))-import Data.Int (Int)-import Data.Maybe (Maybe (..))-import Data.Word (Word)-import Integer.Positive.Unsafe (Positive, addOne, one, toInteger, toNatural)-import Integer.Signed (Signed (..))-import Numeric.Natural (Natural)-import Prelude (Integer)--import qualified Data.Ord as Ord-import qualified Integer.Positive.Unsafe as Unsafe-import qualified Prelude as Bounded (Bounded (..))-import qualified Prelude as Num (Integral (..), Num (..))--fromInteger :: Integer -> Maybe Positive-fromInteger x = if x Ord.> 0 then Just (Unsafe.fromInteger x) else Nothing--fromNatural :: Natural -> Maybe Positive-fromNatural x = case x of 0 -> Nothing; _ -> Just (Unsafe.fromNatural x)--toInt :: Positive -> Maybe Int-toInt x = if ok then Just (Num.fromInteger x') else Nothing- where- ok = x' Ord.<= Num.toInteger (Bounded.maxBound :: Int)- x' = Num.toInteger x--fromInt :: Int -> Maybe Positive-fromInt x = if ok then Just (Num.fromInteger x') else Nothing- where- ok = x' Ord.>= 1- x' = Num.toInteger x--toWord :: Positive -> Maybe Word-toWord x = if ok then Just (Num.fromInteger x') else Nothing- where- ok = x' Ord.<= Num.toInteger (Bounded.maxBound :: Word)- x' = Num.toInteger x--fromWord :: Word -> Maybe Positive-fromWord x = if ok then Just (Num.fromInteger x') else Nothing- where- ok = x' Ord.>= 1- x' = Num.toInteger x--subtract :: Positive -> Positive -> Signed-subtract a b = case Ord.compare a b of- Ord.EQ -> Zero- Ord.GT -> Plus $ Unsafe.subtract a b- Ord.LT -> Minus $ Unsafe.subtract b a--subtractOne :: Positive -> Natural-subtractOne x = toNatural x Num.- 1--toSigned :: Positive -> Signed-toSigned = Plus--fromSigned :: Signed -> Maybe Positive-fromSigned (Plus x) = Just x-fromSigned _ = Nothing
− integer-types/Integer/Positive/Unsafe.hs
@@ -1,160 +0,0 @@-{-# language Unsafe #-}--{- | This module is unsafe not merely in the sense that it contains partial-functions, but moreover than it is capable of constructing the invalid-'Positive' value @'FromNatural' 0@ representing zero, which is not positive.-When a function has "checked" in its name, this indicates that it is partial but-will never construct an invalid 'Positive'. -}--module Integer.Positive.Unsafe- (- {- * Type -} Positive (FromNatural),- {- * Conversion -}- {- ** Natural -} toNatural, fromNatural, fromNaturalChecked,- {- ** Integer -} toInteger, fromInteger, fromIntegerChecked,- {- ** Int -} toInt, fromInt, fromIntChecked,- {- * Arithmetic -} subtract, subtractChecked,- {- * One (1) -} one, addOne, subtractOne, subtractOneChecked,- )- where--import Data.Function (const, id, ($), (.))-import Integer.BoundedBelow (BoundedBelow)-import Numeric.Natural (Natural)-import Prelude (Enum, Eq, Int, Integer, Integral, Num, Ord, Real, Show)--import qualified Control.DeepSeq as DeepSeq-import qualified Control.Exception as Exception-import qualified Data.Bits as Bits-import qualified Data.List as List-import qualified Data.Maybe as Maybe-import qualified Data.Ord as Ord-import qualified Integer.BoundedBelow as BoundedBelow-import qualified Prelude as Enum (Enum (..))-import qualified Prelude as Num (Integral (..), Num (..), Real (..),- fromIntegral)-import qualified Text.Show as Show--newtype Positive = FromNatural{ toNatural :: Natural } deriving (Eq, Ord)--instance DeepSeq.NFData Positive where rnf (FromNatural x) = DeepSeq.rnf x--fromNatural :: Natural -> Positive-fromNatural = FromNatural--fromNaturalChecked :: Natural -> Positive-fromNaturalChecked x = case x of 0 -> Exception.throw Exception.Underflow; _ -> fromNatural x--toInteger :: Positive -> Integer-toInteger = Num.toInteger . toNatural--fromInteger :: Integer -> Positive-fromInteger = fromNatural . Num.fromInteger--fromIntegerChecked :: Integer -> Positive-fromIntegerChecked x = if x Ord.>= 1 then fromInteger x else Exception.throw Exception.Underflow--add :: Positive -> Positive -> Positive-add a b = fromNatural (toNatural a Num.+ toNatural b)--subtract :: Positive -> Positive -> Positive-subtract a b = fromNatural (toNatural a Num.- toNatural b)--subtractChecked :: Positive -> Positive -> Positive-subtractChecked a b = if a Ord.> b then subtract a b else Exception.throw Exception.Underflow--multiply :: Positive -> Positive -> Positive-multiply a b = fromNatural (toNatural a Num.* toNatural b)--one :: Positive-one = fromNatural 1--addOne :: Positive -> Positive-addOne = fromNatural . (Num.+ 1) . toNatural--subtractOne :: Positive -> Positive-subtractOne = fromNatural . (Num.- 1) . toNatural--subtractOneChecked :: Positive -> Positive-subtractOneChecked x = case x of { 1 -> Exception.throw Exception.Underflow; _ -> subtractOne x }--toInt :: Positive -> Int-toInt = Num.fromIntegral . toNatural--toIntChecked :: Positive -> Int-toIntChecked = Maybe.fromMaybe (Exception.throw Exception.Overflow) . Bits.toIntegralSized . toNatural--fromInt :: Int -> Positive-fromInt = fromNatural . Num.fromIntegral--fromIntChecked :: Int -> Positive-fromIntChecked x = case Num.signum x of { 1 -> fromInt x; _ -> Exception.throw Exception.Underflow }--enumFrom :: Positive -> [Positive]-enumFrom = List.map fromNatural . Enum.enumFrom . toNatural--enumFromTo :: Positive -> Positive -> [Positive]-enumFromTo a b = List.map fromNatural $ Enum.enumFromTo (toNatural a) (toNatural b)--enumFromThen :: Positive -> Positive -> [Positive]-enumFromThen a b = if a Ord.< b then ascending else descending- where- ascending = List.map fromNatural $ Enum.enumFromThen (toNatural a) (toNatural b)- descending = List.map fromInteger $ List.takeWhile (Ord.>= 1) $- Enum.enumFromThen (toInteger a) (toInteger b)--enumFromThenTo :: Positive -> Positive -> Positive -> [Positive]-enumFromThenTo a b c = if a Ord.< b then ascending else descending- where- ascending = List.map fromNatural $ Enum.enumFromThenTo (toNatural a) (toNatural b) (toNatural c)- descending = List.map fromInteger $ List.takeWhile (Ord.>= 1) $- Enum.enumFromThenTo (toInteger a) (toInteger b) (toInteger c)--type Div a = a -> a -> (a, a)--divisionOp :: Div Natural -> Div Positive-divisionOp o a b =- let (q, r) = o (toNatural a) (toNatural b)- in (fromNaturalChecked q, fromNaturalChecked r)--instance BoundedBelow Positive- where- minBound = 1--instance Num Positive- where- abs = id- negate = const (Exception.throw Exception.Underflow)- signum = const (fromNatural 1)- fromInteger = fromIntegerChecked- (+) = add- (*) = multiply- (-) = subtractChecked--instance Enum Positive- where- succ = addOne- pred = subtractOneChecked-- fromEnum = toIntChecked- toEnum = fromIntChecked-- enumFrom = enumFrom- enumFromTo = enumFromTo- enumFromThen = enumFromThen- enumFromThenTo = enumFromThenTo--instance Real Positive- where- toRational = Num.toRational . toInteger--instance Integral Positive- where- toInteger = toInteger- quotRem = divisionOp Num.quotRem- divMod = divisionOp Num.divMod--instance Show Positive- where- show = Show.show . toNatural- showsPrec i = Show.showsPrec i . toNatural
− integer-types/Integer/Sign.hs
@@ -1,24 +0,0 @@-{-# language Safe #-}--module Integer.Sign- (- {- * Type -} Sign (..),- {- * Operations -} negate, multiply,- )- where--import Prelude (Eq, Ord, Show, seq, (==))--import qualified Control.DeepSeq as DeepSeq--data Sign = MinusSign | PlusSign- deriving (Eq, Ord, Show)--instance DeepSeq.NFData Sign where rnf x = seq x ()--negate :: Sign -> Sign-negate PlusSign = MinusSign-negate MinusSign = PlusSign--multiply :: Sign -> Sign -> Sign-multiply a b = if a == b then PlusSign else MinusSign
− integer-types/Integer/Signed.hs
@@ -1,213 +0,0 @@-{-# language Trustworthy #-}--module Integer.Signed- (- {- * Type -} Signed (Zero, NonZero, Plus, Minus, NotPlus, NotMinus),- {- * Conversion -}- {- ** Integer -} toInteger, fromInteger,- {- ** Natural -} toNatural, fromNatural,- {- ** Positive -} toPositive, fromPositive,- {- ** Int -} toInt, fromInt,- {- ** Word -} toWord, fromWord,- )- where--import Data.Function (($), (.))-import Data.Int (Int)-import Data.Maybe (Maybe (..))-import Data.Word (Word)-import Integer.Positive.Unsafe (Positive)-import Integer.Sign (Sign (..))-import Numeric.Natural (Natural)-import Prelude (Enum, Eq, Integer, Integral, Num, Ord, Real, Show, seq)--import qualified Control.DeepSeq as DeepSeq-import qualified Data.List as List-import qualified Data.Ord as Ord-import qualified Integer.Positive.Unsafe as Positive.Unsafe-import qualified Integer.Sign as Sign-import qualified Prelude as Bounded (Bounded (..))-import qualified Prelude as Enum (Enum (..))-import qualified Prelude as Num (Integral (..), Num (..), Real (..))-import qualified Text.Show as Show--data Signed = Zero | NonZero Sign Positive- deriving (Eq)--instance Ord Signed where- compare Zero Zero = Ord.EQ-- compare Zero (Minus _) = Ord.GT- compare Zero (Plus _ ) = Ord.LT- compare (Minus _) Zero = Ord.LT- compare (Plus _) Zero = Ord.GT-- compare (Plus _) (Minus _) = Ord.GT- compare (Minus _) (Plus _) = Ord.LT- compare (Plus a) (Plus b) = Ord.compare a b- compare (Minus a) (Minus b) = Ord.compare b a--instance DeepSeq.NFData Signed where- rnf Zero = ()- rnf (NonZero a b) = a `seq` b `seq` ()--pattern Minus :: Positive -> Signed-pattern Minus x = NonZero MinusSign x-pattern Plus :: Positive -> Signed--pattern Plus x = NonZero PlusSign x---- | A 'Signed' that is either zero or positive-pattern NotMinus :: Natural -> Signed-pattern NotMinus x <- (toNatural -> Just x)- where NotMinus = fromNatural---- | A 'Signed' that is either zero or negative;--- the 'Natural' gives the magnitude of the negative-pattern NotPlus :: Natural -> Signed-pattern NotPlus x <- ((toNatural . negate) -> Just x)- where NotPlus = negate . fromNatural--{-# complete Zero, Minus, Plus #-}-{-# complete Plus, NotPlus #-}-{-# complete Minus, NotMinus #-}--fromPositive :: Positive -> Signed-fromPositive = Plus--toPositive :: Signed -> Maybe Positive-toPositive (Plus x) = Just x-toPositive _ = Nothing--fromNatural :: Natural -> Signed-fromNatural 0 = Zero-fromNatural x = Plus $ Positive.Unsafe.fromNatural x--toNatural :: Signed -> Maybe Natural-toNatural (Minus _) = Nothing-toNatural Zero = Just 0-toNatural (Plus x) = Just (Positive.Unsafe.toNatural x)--add :: Signed -> Signed -> Signed-add Zero x = x-add x Zero = x-add (NonZero sa a) (NonZero sb b) = case (sa, sb) of- (PlusSign, PlusSign) -> Plus $ a Num.+ b- (MinusSign, MinusSign) -> Minus $ a Num.+ b-- (MinusSign, PlusSign) -> case Ord.compare a b of- Ord.EQ -> Zero- Ord.LT -> Plus $ Positive.Unsafe.subtract b a- Ord.GT -> Minus $ Positive.Unsafe.subtract a b-- (PlusSign, MinusSign) -> case Ord.compare a b of- Ord.EQ -> Zero- Ord.LT -> Minus $ Positive.Unsafe.subtract b a- Ord.GT -> Plus $ Positive.Unsafe.subtract a b--negate :: Signed -> Signed-negate Zero = Zero-negate (NonZero s x) = NonZero (Sign.negate s) x--multiply :: Signed -> Signed -> Signed-multiply Zero _ = Zero-multiply _ Zero = Zero-multiply (NonZero sa a) (NonZero sb b) =- NonZero (Sign.multiply sa sb) (a Num.* b)--abs :: Signed -> Signed-abs Zero = Zero-abs x@(NonZero s p) = case s of- PlusSign -> x- MinusSign -> NonZero PlusSign p--signum :: Signed -> Signed-signum Zero = Zero-signum (NonZero s _) = NonZero s Positive.Unsafe.one--fromInteger :: Integer -> Signed-fromInteger x = case Ord.compare x 0 of- Ord.EQ -> Zero- Ord.LT -> Minus $ Positive.Unsafe.fromInteger $ Num.abs x- Ord.GT -> Plus $ Positive.Unsafe.fromInteger x--toInteger :: Signed -> Integer-toInteger Zero = 0-toInteger (Plus x) = Positive.Unsafe.toInteger x-toInteger (Minus x) = Num.negate $ Positive.Unsafe.toInteger x--toInt :: Signed -> Maybe Int-toInt x = case x of- Zero -> Just 0- Plus p -> if ok then Just (Num.fromInteger i) else Nothing- where- ok = i Ord.<= Num.toInteger (Bounded.maxBound :: Int)- i = Positive.Unsafe.toInteger p- Minus p -> if ok then Just (Num.fromInteger i) else Nothing- where- ok = i Ord.>= Num.toInteger (Bounded.minBound :: Int)- i = Num.negate (Positive.Unsafe.toInteger p)--fromInt :: Int -> Signed-fromInt x = case Ord.compare x 0 of- Ord.EQ -> Zero- Ord.GT -> Plus $ Positive.Unsafe.fromInt x- Ord.LT -> Minus $ Positive.Unsafe.fromInteger $ Num.negate $ Num.toInteger x--toWord :: Signed -> Maybe Word-toWord x = case x of- Zero -> Just 0- Plus p -> if ok then Just (Num.fromInteger i) else Nothing- where- ok = i Ord.<= Num.toInteger (Bounded.maxBound :: Word)- i = Positive.Unsafe.toInteger p- Minus _ -> Nothing--fromWord :: Word -> Signed-fromWord x = case x of- 0 -> Zero- _ -> Plus $ Positive.Unsafe.fromInteger (Num.toInteger x)--type Div a = a -> a -> (a, a)--divisionOp :: Div Integer -> Div Signed-divisionOp o a b =- let (q, r) = o (toInteger a) (toInteger b)- in (fromInteger q, fromInteger r)--instance Num Signed- where- (+) = add- (*) = multiply- negate = negate- abs = abs- signum = signum- fromInteger = fromInteger--instance Enum Signed- where- pred = fromInteger . Enum.pred . toInteger- succ = fromInteger . Enum.succ . toInteger-- toEnum = fromInteger . Enum.toEnum- fromEnum = Enum.fromEnum . toInteger-- enumFrom a = List.map fromInteger $ Enum.enumFrom (toInteger a)- enumFromTo a b = List.map fromInteger $ Enum.enumFromTo (toInteger a) (toInteger b)- enumFromThen a b = List.map fromInteger $ Enum.enumFromThen (toInteger a) (toInteger b)- enumFromThenTo a b c = List.map fromInteger $ Enum.enumFromThenTo (toInteger a) (toInteger b) (toInteger c)--instance Real Signed- where- toRational = Num.toRational . toInteger--instance Integral Signed- where- toInteger = toInteger- quotRem = divisionOp Num.quotRem- divMod = divisionOp Num.divMod--instance Show Signed- where- show = Show.show . Num.toInteger- showsPrec i = Show.showsPrec i . Num.toInteger
− integer-types/Integer/Subtraction.hs
@@ -1,47 +0,0 @@-module Integer.Subtraction- (- Subtraction (subtractInteger, subtractSigned),- Subtraction' (subtract),- )- where--import Integer.Integer (Integer)-import Integer.Natural (Natural)-import Integer.Positive (Positive)-import Integer.Signed (Signed)--import qualified Integer.Natural as Natural-import qualified Integer.Positive as Positive-import qualified Integer.Signed as Signed-import qualified Prelude as Num (Num (..))---- | Domain of a subtraction operation-class Subtraction a where- subtractInteger :: a -> a -> Integer- subtractInteger a b = Signed.toInteger (subtractSigned a b)-- subtractSigned :: a -> a -> Signed- subtractSigned a b = Signed.fromInteger (subtractInteger a b)--instance Subtraction Integer where- subtractInteger = (Num.-)--instance Subtraction Signed where- subtractInteger a b = (Num.-) (Signed.toInteger a) (Signed.toInteger b)- subtractSigned = (Num.-)--instance Subtraction Natural where- subtractSigned = Natural.subtract--instance Subtraction Positive where- subtractSigned = Positive.subtract---- | Codomain of a subtraction operation-class Subtraction' b where- subtract :: Subtraction a => a -> a -> b--instance Subtraction' Integer where- subtract = subtractInteger--instance Subtraction' Signed where- subtract = subtractSigned
+ library/Integer.hs view
@@ -0,0 +1,22 @@+module Integer+ (+ {- ** Types -} Integer, Natural, Positive,+ Signed (Zero, NonZero, Minus, Plus), Sign (MinusSign, PlusSign),+ {- ** Subtraction -} Subtraction (subtractInteger, subtractSigned), Subtraction' (subtract),+ {- ** Conversion -} IntegerNarrow (narrow), IntegerConvert (convert), IntegerEquiv, yolo, ConvertWithFinite (toInt, fromInt, toWord, fromWord), Finite (..),+ {- ** Lower bound -} BoundedBelow (minBound),+ )+ where++import Integer.BoundedBelow (BoundedBelow (minBound))+import Integer.Conversion (IntegerConvert (convert), IntegerEquiv,+ IntegerNarrow (narrow), yolo)+import Integer.Finite (ConvertWithFinite (fromInt, fromWord, toInt, toWord),+ Finite (..))+import Integer.Integer (Integer)+import Integer.Natural (Natural)+import Integer.Positive (Positive)+import Integer.Sign (Sign (MinusSign, PlusSign))+import Integer.Signed (Signed (Minus, NonZero, Plus, Zero))+import Integer.Subtraction (Subtraction (subtractInteger, subtractSigned),+ Subtraction' (subtract))
+ library/Integer/BoundedBelow.hs view
@@ -0,0 +1,11 @@+module Integer.BoundedBelow where++import Numeric.Natural (Natural)++class BoundedBelow a where+ minBound :: a++instance BoundedBelow Natural where+ minBound = 0++
+ library/Integer/Conversion.hs view
@@ -0,0 +1,91 @@+module Integer.Conversion+ (+ IntegerNarrow (narrow),+ IntegerConvert (convert),+ IntegerEquiv,+ yolo,+ )+ where++import Essentials++import Integer.Integer (Integer)+import Integer.Natural (Natural)+import Integer.Positive (Positive)+import Integer.Signed (Signed)++import qualified Integer.Integer as Integer+import qualified Integer.Natural as Natural+import qualified Integer.Positive as Positive+import qualified Integer.Signed as Signed+import qualified Prelude as Num (Integral (..), Num (..))++class IntegerNarrow a b => IntegerConvert a b where+ convert :: a -> b++class IntegerNarrow a b where+ narrow :: a -> Maybe b++class (IntegerConvert a b, IntegerConvert b a) => IntegerEquiv a b+++--- Isomorphisms ---++instance IntegerEquiv Integer Integer+instance IntegerConvert Integer Integer where convert = id+instance IntegerNarrow Integer Integer where narrow = Just++instance IntegerEquiv Natural Natural+instance IntegerConvert Natural Natural where convert = id+instance IntegerNarrow Natural Natural where narrow = Just++instance IntegerEquiv Positive Positive+instance IntegerConvert Positive Positive where convert = id+instance IntegerNarrow Positive Positive where narrow = Just++instance IntegerEquiv Signed Signed+instance IntegerConvert Signed Signed where convert = id+instance IntegerNarrow Signed Signed where narrow = Just++instance IntegerEquiv Integer Signed+instance IntegerConvert Integer Signed where convert = Integer.toSigned+instance IntegerNarrow Integer Signed where narrow = Just . convert++instance IntegerEquiv Signed Integer+instance IntegerConvert Signed Integer where convert = Signed.toInteger+instance IntegerNarrow Signed Integer where narrow = Just . convert+++--- Prisms ---++instance IntegerNarrow Integer Natural where narrow = Integer.toNatural+instance IntegerNarrow Natural Integer where narrow = Just . convert+instance IntegerConvert Natural Integer where convert = Natural.toInteger++instance IntegerNarrow Signed Natural where narrow = Signed.toNatural+instance IntegerNarrow Natural Signed where narrow = Just . convert+instance IntegerConvert Natural Signed where convert = Natural.toSigned++instance IntegerNarrow Integer Positive where narrow = Integer.toPositive+instance IntegerNarrow Positive Integer where narrow = Just . convert+instance IntegerConvert Positive Integer where convert = Positive.toInteger++instance IntegerNarrow Natural Positive where narrow = Natural.toPositive+instance IntegerNarrow Positive Natural where narrow = Just . convert+instance IntegerConvert Positive Natural where convert = Positive.toNatural++instance IntegerNarrow Signed Positive where narrow = Signed.toPositive+instance IntegerNarrow Positive Signed where narrow = Just . convert+instance IntegerConvert Positive Signed where convert = Positive.toSigned+++--- lol ---++-- | Partial conversion between 'Num.Integral' types via 'Integer'+--+-- @+-- yolo = 'Num.fromInteger' . 'Num.toInteger'+-- @+--+yolo :: (Num.Integral a, Num.Num b) => a -> b+yolo = Num.fromInteger . Num.toInteger
+ library/Integer/Finite.hs view
@@ -0,0 +1,59 @@+module Integer.Finite where++import Essentials++import Data.Int (Int)+import Data.Word (Word)+import Integer.Integer (Integer)+import Integer.Natural (Natural)+import Integer.Positive (Positive)+import Integer.Signed (Signed)+import Prelude (Integral)++import qualified Data.Maybe as Maybe+import qualified Integer.Integer as Integer+import qualified Integer.Natural as Natural+import qualified Integer.Positive as Positive+import qualified Integer.Signed as Signed++class ConvertWithFinite a where+ toWord :: a -> Maybe Word+ fromWord :: Word -> Maybe a+ toInt :: a -> Maybe Int+ fromInt :: Int -> Maybe a++instance ConvertWithFinite Natural where+ toWord = Natural.toWord+ fromWord = Maybe.Just . Natural.fromWord+ toInt = Natural.toInt+ fromInt = Natural.fromInt++instance ConvertWithFinite Positive where+ toWord = Positive.toWord+ fromWord = Positive.fromWord+ toInt = Positive.toInt+ fromInt = Positive.fromInt++instance ConvertWithFinite Integer where+ toWord = Integer.toWord+ fromWord = Maybe.Just . Integer.fromWord+ toInt = Integer.toInt+ fromInt = Maybe.Just . Integer.fromInt++instance ConvertWithFinite Signed where+ toWord = Signed.toWord+ fromWord = Maybe.Just . Signed.fromWord+ toInt = Signed.toInt+ fromInt = Maybe.Just . Signed.fromInt++class (Bounded b, Integral b) => Finite b where+ toFinite :: ConvertWithFinite a => a -> Maybe b+ fromFinite :: ConvertWithFinite a => b -> Maybe a++instance Finite Int where+ toFinite = toInt+ fromFinite = fromInt++instance Finite Word where+ toFinite = toWord+ fromFinite = fromWord
+ library/Integer/Integer.hs view
@@ -0,0 +1,64 @@+module Integer.Integer+ (+ {- * Type -} Integer,+ {- * Conversion -}+ {- ** Positive -} toPositive, fromPositive,+ {- ** Natural -} toNatural, fromNatural,+ {- ** Signed -} toSigned, fromSigned,+ {- ** Int -} toInt, fromInt,+ {- ** Word -} toWord, fromWord,+ )+ where++import Essentials++import Data.Int (Int)+import Data.Word (Word)+import Integer.Positive (Positive)+import Integer.Signed (Signed (..))+import Numeric.Natural (Natural)+import Prelude (Integer)++import qualified Data.Bool as Bool+import qualified Data.Ord as Ord+import qualified Integer.Natural as Natural+import qualified Integer.Positive as Positive+import qualified Integer.Signed as Signed+import qualified Prelude as Bounded (Bounded (..))+import qualified Prelude as Num (Integral (..), Num (..))++toPositive :: Integer -> Maybe Positive+toPositive = Positive.fromInteger++fromPositive :: Positive -> Integer+fromPositive = Positive.toInteger++toNatural :: Integer -> Maybe Natural+toNatural = Natural.fromInteger++fromNatural :: Natural -> Integer+fromNatural = Natural.toInteger++toSigned :: Integer -> Signed+toSigned = Signed.fromInteger++fromSigned :: Signed -> Integer+fromSigned = Signed.toInteger++toInt :: Integer -> Maybe Int+toInt x = if ok then Just (Num.fromInteger x) else Nothing+ where+ ok = x Ord.>= Num.toInteger (Bounded.minBound :: Int) Bool.&&+ x Ord.<= Num.toInteger (Bounded.maxBound :: Int)++fromInt :: Int -> Integer+fromInt = Num.toInteger++toWord :: Integer -> Maybe Word+toWord x = if ok then Just (Num.fromInteger x) else Nothing+ where+ ok = x Ord.>= Num.toInteger (Bounded.minBound :: Word) Bool.&&+ x Ord.<= Num.toInteger (Bounded.maxBound :: Word)++fromWord :: Word -> Integer+fromWord = Num.toInteger
+ library/Integer/Natural.hs view
@@ -0,0 +1,84 @@+module Integer.Natural+ (+ {- * Type -} Natural,+ {- * Subtraction -} subtract,+ {- * Conversion -}+ {- ** Positive -} toPositive, fromPositive,+ {- ** Integer -} toInteger, fromInteger,+ {- ** Signed -} toSigned, fromSigned,+ {- ** Int -} toInt, fromInt,+ {- ** Word -} toWord, fromWord,+ {- * One (1) -} one, addOne, subtractOne,+ )+ where++import Essentials++import Data.Int (Int)+import Data.Word (Word)+import Integer.Signed (Signed (..))+import Numeric.Natural (Natural)+import Prelude (Integer)++import qualified Data.Ord as Ord+import qualified Integer.Positive as Positive+import qualified Integer.Positive.Unsafe as Positive.Unsafe+import qualified Integer.Signed as Signed+import qualified Prelude as Bounded (Bounded (..))+import qualified Prelude as Num (Integral (..), Num (..))++toPositive :: Natural -> Maybe Positive.Unsafe.Positive+toPositive = Positive.fromNatural++fromPositive :: Positive.Unsafe.Positive -> Natural+fromPositive = Positive.toNatural++fromInteger :: Integer -> Maybe Natural+fromInteger x = if x Ord.>= 0 then Just (Num.fromInteger x) else Nothing++toInteger :: Natural -> Integer+toInteger = Num.toInteger++toSigned :: Natural -> Signed+toSigned = Signed.fromNatural++fromSigned :: Signed -> Maybe Natural+fromSigned = Signed.toNatural++toInt :: Natural -> Maybe Int+toInt x = if ok then Just (Num.fromInteger x') else Nothing+ where+ ok = x' Ord.<= Num.toInteger (Bounded.maxBound :: Int)+ x' = Num.toInteger x++fromInt :: Int -> Maybe Natural+fromInt x = if ok then Just (Num.fromInteger x') else Nothing+ where+ ok = x Ord.>= 0+ x' = Num.toInteger x++toWord :: Natural -> Maybe Word+toWord x = if ok then Just (Num.fromInteger x') else Nothing+ where+ ok = x' Ord.<= Num.toInteger (Bounded.maxBound :: Word)+ x' = Num.toInteger x++fromWord :: Word -> Natural+fromWord x = Num.fromInteger (Num.toInteger x)++subtract :: Natural -> Natural -> Signed+subtract a b = case Ord.compare a b of+ Ord.EQ -> Zero+ Ord.GT -> Plus $ Positive.Unsafe.fromNatural $ (Num.-) a b+ Ord.LT -> Minus $ Positive.Unsafe.fromNatural $ (Num.-) b a++one :: Natural+one = 1++addOne :: Integer -> Integer+addOne = (Num.+ 1)++subtractOne :: Natural -> Maybe Signed+subtractOne x = case x of+ 0 -> Nothing+ p -> Just (subtract p 1)
+ library/Integer/Positive.hs view
@@ -0,0 +1,73 @@+module Integer.Positive+ (+ {- * Type -} Positive,+ {- * Subtraction -} subtract,+ {- * Conversion -}+ {- ** Natural -} toNatural, fromNatural,+ {- ** Integer -} toInteger, fromInteger,+ {- ** Signed -} toSigned, fromSigned,+ {- ** Int -} toInt, fromInt,+ {- ** Word -} toWord, fromWord,+ {- * One (1) -} one, addOne, subtractOne,+ )+ where++import Essentials++import Data.Int (Int)+import Data.Word (Word)+import Integer.Positive.Unsafe (Positive, addOne, one, toInteger, toNatural)+import Integer.Signed (Signed (..))+import Numeric.Natural (Natural)+import Prelude (Integer)++import qualified Data.Ord as Ord+import qualified Integer.Positive.Unsafe as Unsafe+import qualified Prelude as Bounded (Bounded (..))+import qualified Prelude as Num (Integral (..), Num (..))++fromInteger :: Integer -> Maybe Positive+fromInteger x = if x Ord.> 0 then Just (Unsafe.fromInteger x) else Nothing++fromNatural :: Natural -> Maybe Positive+fromNatural x = case x of 0 -> Nothing; _ -> Just (Unsafe.fromNatural x)++toInt :: Positive -> Maybe Int+toInt x = if ok then Just (Num.fromInteger x') else Nothing+ where+ ok = x' Ord.<= Num.toInteger (Bounded.maxBound :: Int)+ x' = Num.toInteger x++fromInt :: Int -> Maybe Positive+fromInt x = if ok then Just (Num.fromInteger x') else Nothing+ where+ ok = x' Ord.>= 1+ x' = Num.toInteger x++toWord :: Positive -> Maybe Word+toWord x = if ok then Just (Num.fromInteger x') else Nothing+ where+ ok = x' Ord.<= Num.toInteger (Bounded.maxBound :: Word)+ x' = Num.toInteger x++fromWord :: Word -> Maybe Positive+fromWord x = if ok then Just (Num.fromInteger x') else Nothing+ where+ ok = x' Ord.>= 1+ x' = Num.toInteger x++subtract :: Positive -> Positive -> Signed+subtract a b = case Ord.compare a b of+ Ord.EQ -> Zero+ Ord.GT -> Plus $ Unsafe.subtract a b+ Ord.LT -> Minus $ Unsafe.subtract b a++subtractOne :: Positive -> Natural+subtractOne x = toNatural x Num.- 1++toSigned :: Positive -> Signed+toSigned = Plus++fromSigned :: Signed -> Maybe Positive+fromSigned (Plus x) = Just x+fromSigned _ = Nothing
+ library/Integer/Positive/Unsafe.hs view
@@ -0,0 +1,159 @@+{- | This module is unsafe not merely in the sense that it contains partial+functions, but moreover than it is capable of constructing the invalid+'Positive' value @'FromNatural' 0@ representing zero, which is not positive.+When a function has "checked" in its name, this indicates that it is partial but+will never construct an invalid 'Positive'. -}++module Integer.Positive.Unsafe+ (+ {- * Type -} Positive (FromNatural),+ {- * Conversion -}+ {- ** Natural -} toNatural, fromNatural, fromNaturalChecked,+ {- ** Integer -} toInteger, fromInteger, fromIntegerChecked,+ {- ** Int -} toInt, fromInt, fromIntChecked,+ {- * Arithmetic -} subtract, subtractChecked,+ {- * One (1) -} one, addOne, subtractOne, subtractOneChecked,+ )+ where++import Essentials ( ($), Enum, Eq, Ord, Show, (.), id )++import Integer.BoundedBelow (BoundedBelow)+import Numeric.Natural (Natural)+import Prelude (Int, Integer, Integral, Num, Real)++import qualified Control.DeepSeq as DeepSeq+import qualified Control.Exception as Exception+import qualified Data.Bits as Bits+import qualified Data.List as List+import qualified Data.Maybe as Maybe+import qualified Data.Ord as Ord+import qualified Integer.BoundedBelow as BoundedBelow+import qualified Prelude as Enum (Enum (..))+import qualified Prelude as Num (Integral (..), Num (..), Real (..),+ fromIntegral)+import qualified Text.Show as Show++newtype Positive = FromNatural{ toNatural :: Natural } deriving (Eq, Ord)++instance DeepSeq.NFData Positive where rnf (FromNatural x) = DeepSeq.rnf x++fromNatural :: Natural -> Positive+fromNatural = FromNatural++fromNaturalChecked :: Natural -> Positive+fromNaturalChecked x = case x of 0 -> Exception.throw Exception.Underflow; _ -> fromNatural x++toInteger :: Positive -> Integer+toInteger = Num.toInteger . toNatural++fromInteger :: Integer -> Positive+fromInteger = fromNatural . Num.fromInteger++fromIntegerChecked :: Integer -> Positive+fromIntegerChecked x = if x Ord.>= 1 then fromInteger x else Exception.throw Exception.Underflow++add :: Positive -> Positive -> Positive+add a b = fromNatural (toNatural a Num.+ toNatural b)++subtract :: Positive -> Positive -> Positive+subtract a b = fromNatural (toNatural a Num.- toNatural b)++subtractChecked :: Positive -> Positive -> Positive+subtractChecked a b = if a Ord.> b then subtract a b else Exception.throw Exception.Underflow++multiply :: Positive -> Positive -> Positive+multiply a b = fromNatural (toNatural a Num.* toNatural b)++one :: Positive+one = fromNatural 1++addOne :: Positive -> Positive+addOne = fromNatural . (Num.+ 1) . toNatural++subtractOne :: Positive -> Positive+subtractOne = fromNatural . (Num.- 1) . toNatural++subtractOneChecked :: Positive -> Positive+subtractOneChecked x = case x of { 1 -> Exception.throw Exception.Underflow; _ -> subtractOne x }++toInt :: Positive -> Int+toInt = Num.fromIntegral . toNatural++toIntChecked :: Positive -> Int+toIntChecked = Maybe.fromMaybe (Exception.throw Exception.Overflow) . Bits.toIntegralSized . toNatural++fromInt :: Int -> Positive+fromInt = fromNatural . Num.fromIntegral++fromIntChecked :: Int -> Positive+fromIntChecked x = case Num.signum x of { 1 -> fromInt x; _ -> Exception.throw Exception.Underflow }++enumFrom :: Positive -> [Positive]+enumFrom = List.map fromNatural . Enum.enumFrom . toNatural++enumFromTo :: Positive -> Positive -> [Positive]+enumFromTo a b = List.map fromNatural $ Enum.enumFromTo (toNatural a) (toNatural b)++enumFromThen :: Positive -> Positive -> [Positive]+enumFromThen a b = if a Ord.< b then ascending else descending+ where+ ascending = List.map fromNatural $ Enum.enumFromThen (toNatural a) (toNatural b)+ descending = List.map fromInteger $ List.takeWhile (Ord.>= 1) $+ Enum.enumFromThen (toInteger a) (toInteger b)++enumFromThenTo :: Positive -> Positive -> Positive -> [Positive]+enumFromThenTo a b c = if a Ord.< b then ascending else descending+ where+ ascending = List.map fromNatural $ Enum.enumFromThenTo (toNatural a) (toNatural b) (toNatural c)+ descending = List.map fromInteger $ List.takeWhile (Ord.>= 1) $+ Enum.enumFromThenTo (toInteger a) (toInteger b) (toInteger c)++type Div a = a -> a -> (a, a)++divisionOp :: Div Natural -> Div Positive+divisionOp o a b =+ let (q, r) = o (toNatural a) (toNatural b)+ in (fromNaturalChecked q, fromNaturalChecked r)++instance BoundedBelow Positive+ where+ minBound = 1++instance Num Positive+ where+ abs = id+ negate = \_ -> Exception.throw Exception.Underflow+ signum = \_ -> fromNatural 1+ fromInteger = fromIntegerChecked+ (+) = add+ (*) = multiply+ (-) = subtractChecked++instance Enum Positive+ where+ succ = addOne+ pred = subtractOneChecked++ fromEnum = toIntChecked+ toEnum = fromIntChecked++ enumFrom = enumFrom+ enumFromTo = enumFromTo+ enumFromThen = enumFromThen+ enumFromThenTo = enumFromThenTo++instance Real Positive+ where+ toRational = Num.toRational . toInteger++instance Integral Positive+ where+ toInteger = toInteger+ quotRem = divisionOp Num.quotRem+ divMod = divisionOp Num.divMod++instance Show Positive+ where+ show = Show.show . toNatural+ showsPrec i = Show.showsPrec i . toNatural
+ library/Integer/Sign.hs view
@@ -0,0 +1,24 @@+module Integer.Sign+ (+ {- * Type -} Sign (..),+ {- * Operations -} negate, multiply,+ )+ where++import Essentials++import Prelude (seq)++import qualified Control.DeepSeq as DeepSeq++data Sign = MinusSign | PlusSign+ deriving (Eq, Ord, Show)++instance DeepSeq.NFData Sign where rnf x = seq x ()++negate :: Sign -> Sign+negate PlusSign = MinusSign+negate MinusSign = PlusSign++multiply :: Sign -> Sign -> Sign+multiply a b = if a == b then PlusSign else MinusSign
+ library/Integer/Signed.hs view
@@ -0,0 +1,211 @@+module Integer.Signed+ (+ {- * Type -} Signed (Zero, NonZero, Plus, Minus, NotPlus, NotMinus),+ {- * Conversion -}+ {- ** Integer -} toInteger, fromInteger,+ {- ** Natural -} toNatural, fromNatural,+ {- ** Positive -} toPositive, fromPositive,+ {- ** Int -} toInt, fromInt,+ {- ** Word -} toWord, fromWord,+ )+ where++import Essentials++import Data.Int (Int)+import Data.Word (Word)+import Integer.Positive.Unsafe (Positive)+import Integer.Sign (Sign (..))+import Numeric.Natural (Natural)+import Prelude (Integer, Integral, Num, Real, seq)++import qualified Control.DeepSeq as DeepSeq+import qualified Data.List as List+import qualified Data.Ord as Ord+import qualified Integer.Positive.Unsafe as Positive.Unsafe+import qualified Integer.Sign as Sign+import qualified Prelude as Bounded (Bounded (..))+import qualified Prelude as Enum (Enum (..))+import qualified Prelude as Num (Integral (..), Num (..), Real (..))+import qualified Text.Show as Show++data Signed = Zero | NonZero Sign Positive+ deriving (Eq)++instance Ord Signed where+ compare Zero Zero = Ord.EQ++ compare Zero (Minus _) = Ord.GT+ compare Zero (Plus _ ) = Ord.LT+ compare (Minus _) Zero = Ord.LT+ compare (Plus _) Zero = Ord.GT++ compare (Plus _) (Minus _) = Ord.GT+ compare (Minus _) (Plus _) = Ord.LT+ compare (Plus a) (Plus b) = Ord.compare a b+ compare (Minus a) (Minus b) = Ord.compare b a++instance DeepSeq.NFData Signed where+ rnf Zero = ()+ rnf (NonZero a b) = a `seq` b `seq` ()++pattern Minus :: Positive -> Signed+pattern Minus x = NonZero MinusSign x+pattern Plus :: Positive -> Signed++pattern Plus x = NonZero PlusSign x++-- | A 'Signed' that is either zero or positive+pattern NotMinus :: Natural -> Signed+pattern NotMinus x <- (toNatural -> Just x)+ where NotMinus = fromNatural++-- | A 'Signed' that is either zero or negative;+-- the 'Natural' gives the magnitude of the negative+pattern NotPlus :: Natural -> Signed+pattern NotPlus x <- ((toNatural . negate) -> Just x)+ where NotPlus = negate . fromNatural++{-# complete Zero, Minus, Plus #-}+{-# complete Plus, NotPlus #-}+{-# complete Minus, NotMinus #-}++fromPositive :: Positive -> Signed+fromPositive = Plus++toPositive :: Signed -> Maybe Positive+toPositive (Plus x) = Just x+toPositive _ = Nothing++fromNatural :: Natural -> Signed+fromNatural 0 = Zero+fromNatural x = Plus $ Positive.Unsafe.fromNatural x++toNatural :: Signed -> Maybe Natural+toNatural (Minus _) = Nothing+toNatural Zero = Just 0+toNatural (Plus x) = Just (Positive.Unsafe.toNatural x)++add :: Signed -> Signed -> Signed+add Zero x = x+add x Zero = x+add (NonZero sa a) (NonZero sb b) = case (sa, sb) of+ (PlusSign, PlusSign) -> Plus $ a Num.+ b+ (MinusSign, MinusSign) -> Minus $ a Num.+ b++ (MinusSign, PlusSign) -> case Ord.compare a b of+ Ord.EQ -> Zero+ Ord.LT -> Plus $ Positive.Unsafe.subtract b a+ Ord.GT -> Minus $ Positive.Unsafe.subtract a b++ (PlusSign, MinusSign) -> case Ord.compare a b of+ Ord.EQ -> Zero+ Ord.LT -> Minus $ Positive.Unsafe.subtract b a+ Ord.GT -> Plus $ Positive.Unsafe.subtract a b++negate :: Signed -> Signed+negate Zero = Zero+negate (NonZero s x) = NonZero (Sign.negate s) x++multiply :: Signed -> Signed -> Signed+multiply Zero _ = Zero+multiply _ Zero = Zero+multiply (NonZero sa a) (NonZero sb b) =+ NonZero (Sign.multiply sa sb) (a Num.* b)++abs :: Signed -> Signed+abs Zero = Zero+abs x@(NonZero s p) = case s of+ PlusSign -> x+ MinusSign -> NonZero PlusSign p++signum :: Signed -> Signed+signum Zero = Zero+signum (NonZero s _) = NonZero s Positive.Unsafe.one++fromInteger :: Integer -> Signed+fromInteger x = case Ord.compare x 0 of+ Ord.EQ -> Zero+ Ord.LT -> Minus $ Positive.Unsafe.fromInteger $ Num.abs x+ Ord.GT -> Plus $ Positive.Unsafe.fromInteger x++toInteger :: Signed -> Integer+toInteger Zero = 0+toInteger (Plus x) = Positive.Unsafe.toInteger x+toInteger (Minus x) = Num.negate $ Positive.Unsafe.toInteger x++toInt :: Signed -> Maybe Int+toInt x = case x of+ Zero -> Just 0+ Plus p -> if ok then Just (Num.fromInteger i) else Nothing+ where+ ok = i Ord.<= Num.toInteger (Bounded.maxBound :: Int)+ i = Positive.Unsafe.toInteger p+ Minus p -> if ok then Just (Num.fromInteger i) else Nothing+ where+ ok = i Ord.>= Num.toInteger (Bounded.minBound :: Int)+ i = Num.negate (Positive.Unsafe.toInteger p)++fromInt :: Int -> Signed+fromInt x = case Ord.compare x 0 of+ Ord.EQ -> Zero+ Ord.GT -> Plus $ Positive.Unsafe.fromInt x+ Ord.LT -> Minus $ Positive.Unsafe.fromInteger $ Num.negate $ Num.toInteger x++toWord :: Signed -> Maybe Word+toWord x = case x of+ Zero -> Just 0+ Plus p -> if ok then Just (Num.fromInteger i) else Nothing+ where+ ok = i Ord.<= Num.toInteger (Bounded.maxBound :: Word)+ i = Positive.Unsafe.toInteger p+ Minus _ -> Nothing++fromWord :: Word -> Signed+fromWord x = case x of+ 0 -> Zero+ _ -> Plus $ Positive.Unsafe.fromInteger (Num.toInteger x)++type Div a = a -> a -> (a, a)++divisionOp :: Div Integer -> Div Signed+divisionOp o a b =+ let (q, r) = o (toInteger a) (toInteger b)+ in (fromInteger q, fromInteger r)++instance Num Signed+ where+ (+) = add+ (*) = multiply+ negate = negate+ abs = abs+ signum = signum+ fromInteger = fromInteger++instance Enum Signed+ where+ pred = fromInteger . Enum.pred . toInteger+ succ = fromInteger . Enum.succ . toInteger++ toEnum = fromInteger . Enum.toEnum+ fromEnum = Enum.fromEnum . toInteger++ enumFrom a = List.map fromInteger $ Enum.enumFrom (toInteger a)+ enumFromTo a b = List.map fromInteger $ Enum.enumFromTo (toInteger a) (toInteger b)+ enumFromThen a b = List.map fromInteger $ Enum.enumFromThen (toInteger a) (toInteger b)+ enumFromThenTo a b c = List.map fromInteger $ Enum.enumFromThenTo (toInteger a) (toInteger b) (toInteger c)++instance Real Signed+ where+ toRational = Num.toRational . toInteger++instance Integral Signed+ where+ toInteger = toInteger+ quotRem = divisionOp Num.quotRem+ divMod = divisionOp Num.divMod++instance Show Signed+ where+ show = Show.show . Num.toInteger+ showsPrec i = Show.showsPrec i . Num.toInteger
+ library/Integer/Subtraction.hs view
@@ -0,0 +1,47 @@+module Integer.Subtraction+ (+ Subtraction (subtractInteger, subtractSigned),+ Subtraction' (subtract),+ )+ where++import Integer.Integer (Integer)+import Integer.Natural (Natural)+import Integer.Positive (Positive)+import Integer.Signed (Signed)++import qualified Integer.Natural as Natural+import qualified Integer.Positive as Positive+import qualified Integer.Signed as Signed+import qualified Prelude as Num (Num (..))++-- | Domain of a subtraction operation+class Subtraction a where+ subtractInteger :: a -> a -> Integer+ subtractInteger a b = Signed.toInteger (subtractSigned a b)++ subtractSigned :: a -> a -> Signed+ subtractSigned a b = Signed.fromInteger (subtractInteger a b)++instance Subtraction Integer where+ subtractInteger = (Num.-)++instance Subtraction Signed where+ subtractInteger a b = (Num.-) (Signed.toInteger a) (Signed.toInteger b)+ subtractSigned = (Num.-)++instance Subtraction Natural where+ subtractSigned = Natural.subtract++instance Subtraction Positive where+ subtractSigned = Positive.subtract++-- | Codomain of a subtraction operation+class Subtraction' b where+ subtract :: Subtraction a => a -> a -> b++instance Subtraction' Integer where+ subtract = subtractInteger++instance Subtraction' Signed where+ subtract = subtractSigned
− test-integer-arithmetic/Main.hs
@@ -1,78 +0,0 @@-{-# language TemplateHaskell #-}-{-# options_ghc -fno-warn-missing-signatures #-}--module Main (main) where--import Integer--import Control.Applicative (pure)-import Control.Monad (Monad)-import Data.Eq (Eq)-import Data.Function (($), (.))-import Data.Maybe (Maybe (Just, Nothing))-import Hedgehog ((===))-import Integer.Gen (GenIntegral)-import Prelude (Num, fromInteger, toInteger, ($!), (*), (+), (-))-import Text.Show (Show)--import qualified Control.Exception as Exception (ArithException (Underflow))-import qualified Control.Monad.Catch as Exception (MonadCatch, try)-import qualified Data.Either as Either-import qualified Hedgehog-import qualified Hedgehog.Main as Hedgehog-import qualified Integer.Gen as Gen--main = Hedgehog.defaultMain [Hedgehog.checkSequential $$(Hedgehog.discover)]--testLimit :: Hedgehog.TestLimit-testLimit = 1000--property = Hedgehog.withTests testLimit . Hedgehog.property---- | Assert that a closed binary 'Num' operation behaves the same--- on a type as it does when applied via conversion with 'Integer'-checkNumOp :: forall a m. GenIntegral a => Monad m =>- (forall b. Num b => b -> b -> b) -> Hedgehog.PropertyT m ()-checkNumOp o = do- x :: a <- Hedgehog.forAll Gen.integral- y :: a <- Hedgehog.forAll Gen.integral- x `o` y === fromInteger (toInteger x `o` toInteger y)---- | Assert that 'subtract' in @a@ gives the same result--- as '(-)' via @b@.-checkSubtract :: forall a b m.- (GenIntegral a, Subtraction a, Subtraction' b, Num b) =>- (IntegerConvert a b, IntegerNarrow b a) =>- (Eq b, Show b) =>- Exception.MonadCatch m => Hedgehog.PropertyT m ()-checkSubtract = do- x :: a <- Hedgehog.forAll Gen.integral- y :: a <- Hedgehog.forAll Gen.integral- (subtract x y :: b) === (convert x - convert y :: b)---- | Assert that '(-)' in @a@ gives the same result as--- '(-)' via @Integer@ if the result is within the range--- of @a@, and is undefined otherwise-checkPartialSubtract :: forall a m.- (GenIntegral a, Subtraction a, IntegerNarrow Integer a) =>- Exception.MonadCatch m => Hedgehog.PropertyT m ()-checkPartialSubtract = do- x :: a <- Hedgehog.forAll Gen.integral- y :: a <- Hedgehog.forAll Gen.integral- case narrow (toInteger x - toInteger y) :: Maybe a of- Just z -> x - y === z- Nothing -> do- z <- Exception.try (pure $! x - y)- z === Either.Left Exception.Underflow--prop_add_positive = property $ checkNumOp @Positive (+)-prop_add_signed = property $ checkNumOp @Signed (+)-prop_multiply_positive = property $ checkNumOp @Positive (*)-prop_multiply_signed = property $ checkNumOp @Signed (*)--prop_subtract_natural_signed = property $ checkSubtract @Natural @Signed-prop_subtract_natural_integer = property $ checkSubtract @Natural @Integer-prop_subtract_positive_signed = property $ checkSubtract @Positive @Signed-prop_subtract_positive_integer = property $ checkSubtract @Positive @Integer--prop_partial_subtract_positive = property $ checkPartialSubtract @Positive
− test-integer-conversions/Main.hs
@@ -1,91 +0,0 @@-{-# language TemplateHaskell #-}-{-# options_ghc -fno-warn-missing-signatures #-}--module Main (main) where--import Integer--import Control.Applicative (pure)-import Control.Monad (Monad)-import Data.Eq (Eq)-import Data.Function (($), (.))-import Data.Maybe (Maybe (..))-import Hedgehog (evalMaybe, (===))-import Integer.Gen (GenIntegral)-import Prelude (($!))-import Text.Show (Show)--import qualified Control.Exception as Exception (ArithException (Underflow))-import qualified Control.Monad.Catch as Exception (MonadCatch, try)-import qualified Data.Either as Either-import qualified Data.Ord as Ord-import qualified Hedgehog-import qualified Hedgehog.Main as Hedgehog-import qualified Integer.Gen as Gen-import qualified Prelude as Num (toInteger)--main = Hedgehog.defaultMain [Hedgehog.checkSequential $$(Hedgehog.discover)]--testLimit :: Hedgehog.TestLimit-testLimit = 1000--property = Hedgehog.withTests testLimit . Hedgehog.property---- | Half of an isomorphism test: @review (view x)@ = @x@-checkIso :: forall a b m. (GenIntegral a, IntegerEquiv a b) =>- Monad m => Hedgehog.PropertyT m ()-checkIso = do- x :: a <- Hedgehog.forAll Gen.integral- convert (convert x :: b) === x---- | Half of a prism test: @preview (x review)@ = @Just@-checkConvert :: forall a b m.- (GenIntegral a, IntegerConvert a b, IntegerNarrow b a) =>- Monad m => Hedgehog.PropertyT m ()-checkConvert = do- x :: a <- Hedgehog.forAll Gen.integral- narrow (convert x :: b) === Just x---- | Half of a prism test: @fmap review (preview x)@ = @Just x@--- for @x@ in range, @Nothing@ otherwise-checkNarrow :: forall a b m. (GenIntegral a, BoundedBelow b) =>- (IntegerConvert b a, IntegerNarrow a b) =>- (Show b, Eq b) => Monad m => Hedgehog.PropertyT m ()-checkNarrow = do- x :: a <- Hedgehog.forAll Gen.integral- let y :: Maybe b = narrow x- if x Ord.>= convert (minBound @b)- then do- z <- evalMaybe y- convert z === x- else y === Nothing---- | Like 'checkNarrow @Integer', but tests the partial 'yolo'--- function rather than the safe 'convert' function-checkYolo :: forall a m. (GenIntegral a, BoundedBelow a) =>- Exception.MonadCatch m => Hedgehog.PropertyT m ()-checkYolo = do- x :: Integer <- Hedgehog.forAll Gen.integral- let y :: a = yolo x- if x Ord.>= Num.toInteger (minBound @a)- then yolo y === x- else do- z <- Exception.try (pure $! y)- z === Either.Left Exception.Underflow--prop_iso_integer_signed = property $ checkIso @Integer @Signed-prop_iso_signed_integer = property $ checkIso @Signed @Integer--prop_prism_natural_integer = property $ checkConvert @Natural @Integer-prop_prism_integer_natural = property $ checkNarrow @Integer @Natural-prop_prism_natural_signed = property $ checkConvert @Natural @Signed-prop_prism_signed_natural = property $ checkNarrow @Signed @Natural-prop_prism_positive_integer = property $ checkConvert @Positive @Integer-prop_prism_integer_positive = property $ checkNarrow @Integer @Positive-prop_prism_positive_signed = property $ checkConvert @Positive @Signed-prop_prism_signed_positive = property $ checkNarrow @Signed @Positive-prop_prism_positive_natural = property $ checkConvert @Positive @Natural-prop_prism_natural_positive = property $ checkNarrow @Natural @Positive--prop_yolo_positive = property $ checkYolo @Positive-prop_yolo_natural = property $ checkYolo @Natural
− test-integer-deepseq/Main.hs
@@ -1,40 +0,0 @@-{-# options_ghc -fno-warn-missing-signatures #-}--module Main (main) where--import Integer--import Control.Applicative (pure)-import Control.DeepSeq (NFData, ($!!))-import Control.Exception (Exception, throw)-import Data.Either (Either (..))-import Data.Eq (Eq)-import Data.Function (($))-import Test.Hspec (describe, hspec, it, shouldBe)-import Text.Show (Show)--import qualified Control.Monad.Catch as Exception (MonadCatch, try)--data X = X- deriving (Eq, Show)--instance Exception X--force :: NFData a => Exception.MonadCatch m => a -> m (Either X a)-force x = Exception.try (pure $!! x)--main = hspec $ do- describe "Signed" $ do- describe "deepseq" $ do- it "can succeed" $ do- x <- force (NonZero MinusSign 5)- x `shouldBe` Right (-5)- it "can force an error" $ do- x <- force (throw X :: Signed)- x `shouldBe` Left X- it "can force an error in sign" $ do- x <- force (NonZero (throw X) 5)- x `shouldBe` Left X- it "can force an error in magnitude" $ do- x <- force (NonZero MinusSign (throw X))- x `shouldBe` Left X
− test-integer-enum/Main.hs
@@ -1,71 +0,0 @@-{-# options_ghc -fno-warn-missing-signatures #-}--module Main (main) where--import Integer--import Data.Function (($))-import Data.List (take)-import Test.Hspec (describe, hspec, it, shouldBe)--main = hspec $ do- describe "Positive" $ do- describe "[a ..]" $ do- it "counts upward" $- take 3 [5 :: Positive ..] `shouldBe` [5, 6, 7]- it "can start with 1" $- take 3 [1 :: Positive ..] `shouldBe` [1, 2, 3]- describe "[a .. b]" $ do- it "counts upward" $- [5 .. 8 :: Positive] `shouldBe` [5, 6, 7, 8]- it "can start with 1" $- [1 .. 5 :: Positive] `shouldBe` [1, 2, 3, 4, 5]- it "does not count downward" $ do- [8 .. 5 :: Positive] `shouldBe` []- [8 .. 7 :: Positive] `shouldBe` []- it "can return 1 item" $ do- [3 .. 3 :: Positive] `shouldBe` [3]- [1 .. 1 :: Positive] `shouldBe` [1]- describe "[a, b ..]" $ do- it "can count upward by 1" $ do- take 5 [5, 6 :: Positive ..] `shouldBe` [5, 6, 7, 8, 9]- take 5 [1, 2 :: Positive ..] `shouldBe` [1, 2, 3, 4, 5]- it "can count downward by 1" $- [5, 4 :: Positive ..] `shouldBe` [5, 4, 3, 2, 1]- it "can count upward by 2" $ do- take 5 [5, 7 :: Positive ..] `shouldBe` [5, 7, 9, 11, 13]- take 5 [1, 3 :: Positive ..] `shouldBe` [1, 3, 5, 7, 9]- it "can count downward by 2" $- [9, 7 :: Positive ..] `shouldBe` [9, 7, 5, 3, 1]- it "can count downward by 2 without exactly reaching its lower bound" $- [8, 6 :: Positive ..] `shouldBe` [8, 6, 4, 2]- it "can repeat 1 item indefinitely" $- take 5 [4, 4 :: Positive ..] `shouldBe` [4, 4, 4, 4, 4]- describe "[a, b .. c]" $ do- it "can count upward by 1" $ do- [5, 6 .. 9 :: Positive] `shouldBe` [5, 6, 7, 8, 9]- [1, 2 .. 5 :: Positive] `shouldBe` [1, 2, 3, 4, 5]- it "can count downward by 1" $- [9, 8 .. 5 :: Positive] `shouldBe` [9, 8, 7, 6, 5]- it "can count upward by 2" $ do- [5, 7 .. 11 :: Positive] `shouldBe` [5, 7, 9, 11]- [1, 3 .. 7 :: Positive] `shouldBe` [1, 3, 5, 7]- it "can count upward without exactly reaching its upper bound" $- [5, 7 .. 12 :: Positive] `shouldBe` [5, 7, 9, 11]- it "can count downward by 2" $- [11, 9 .. 5 :: Positive] `shouldBe` [11, 9, 7, 5]- it "can count downward by 2 without exactly reaching its lower bound" $- [11, 9 .. 4 :: Positive] `shouldBe` [11, 9, 7, 5]- it "can count downward with a lower bound of 1" $ do- [7, 5 .. 1 :: Positive] `shouldBe` [7, 5, 3, 1]- [8, 6 .. 1 :: Positive] `shouldBe` [8, 6, 4, 2]- it "can repeat 1 item indefinitely" $ do- take 5 [4, 4 .. 9 :: Positive] `shouldBe` [4, 4, 4, 4, 4]- take 5 [4, 4 .. 4 :: Positive] `shouldBe` [4, 4, 4, 4, 4]- it "can return 1 item" $ do- [4, 5 .. 4 :: Positive] `shouldBe` [4]- [4, 3 .. 4 :: Positive] `shouldBe` [4]- it "can return an empty list" $ do- [4, 4 .. 3 :: Positive] `shouldBe` []- [4, 5 .. 3 :: Positive] `shouldBe` []- [5, 4 .. 6 :: Positive] `shouldBe` []
− test-integer-finite/Main.hs
@@ -1,71 +0,0 @@-{-# language TemplateHaskell #-}-{-# options_ghc -fno-warn-missing-signatures #-}--module Main (main) where--import Integer--import Control.Monad (Monad)-import Data.Eq (Eq)-import Data.Function (($), (.))-import Data.Int (Int)-import Data.Maybe (Maybe (..))-import Data.Word (Word)-import Hedgehog ((===))-import Integer.Gen (GenFinite, GenIntegral)-import Text.Show (Show)--import qualified Data.Bool as Bool-import qualified Data.Ord as Ord-import qualified Hedgehog-import qualified Hedgehog.Main as Hedgehog-import qualified Integer.Gen as Gen-import qualified Prelude as Bounded (Bounded (..))-import qualified Prelude as Num (fromInteger, toInteger)--main = Hedgehog.defaultMain [Hedgehog.checkSequential $$(Hedgehog.discover)]--testLimit :: Hedgehog.TestLimit-testLimit = 1000--property = Hedgehog.withTests testLimit . Hedgehog.property--checkToFinite :: forall a b m. Monad m =>- (ConvertWithFinite a, GenIntegral a, Show a) =>- (Integer.Finite b, Eq b, Show b) =>- Hedgehog.PropertyT m ()-checkToFinite = do- x :: a <- Hedgehog.forAll Gen.integral- let x' = Num.toInteger x- let ok = x' Ord.>= Num.toInteger (Bounded.minBound :: b) Bool.&&- x' Ord.<= Num.toInteger (Bounded.maxBound :: b)- (Integer.toFinite x :: Maybe b) ===- if ok then Just (Num.fromInteger x') else Nothing--checkFromFinite :: forall a b m. Monad m =>- (ConvertWithFinite a, IntegerNarrow Integer a, Eq a, Show a) =>- (Finite b, GenFinite b, Show b) =>- Hedgehog.PropertyT m ()-checkFromFinite = do- x :: b <- Hedgehog.forAll Gen.finite- (Integer.fromFinite x :: Maybe a) === Integer.narrow (Num.toInteger x)--prop_convert_integer_int = property $ checkToFinite @Integer @Int-prop_convert_int_integer = property $ checkFromFinite @Integer @Int-prop_convert_integer_word = property $ checkToFinite @Integer @Word-prop_convert_word_integer = property $ checkFromFinite @Integer @Word--prop_convert_natural_int = property $ checkToFinite @Natural @Int-prop_convert_int_natural = property $ checkFromFinite @Natural @Int-prop_convert_natural_word = property $ checkToFinite @Natural @Word-prop_convert_word_natural = property $ checkFromFinite @Natural @Word--prop_convert_positive_int = property $ checkToFinite @Positive @Int-prop_convert_int_positive = property $ checkFromFinite @Positive @Int-prop_convert_positive_word = property $ checkToFinite @Positive @Word-prop_convert_word_positive = property $ checkFromFinite @Positive @Word--prop_convert_signed_int = property $ checkToFinite @Signed @Int-prop_convert_int_signed = property $ checkFromFinite @Signed @Int-prop_convert_signed_word = property $ checkToFinite @Signed @Word-prop_convert_word_signed = property $ checkFromFinite @Signed @Word
+ test/Integer/Gen.hs view
@@ -0,0 +1,120 @@+module Integer.Gen+ (+ GenIntegral (integral),+ GenFinite (finite),+ astronomical,+ )+ where++import Essentials++import Data.Int (Int)+import Data.Word (Word)+import Integer (BoundedBelow (..), Integer, Natural, Positive, Sign (..),+ Signed (..))++import qualified Hedgehog+import qualified Hedgehog.Gen as Gen+import qualified Hedgehog.Range as Range+import qualified Prelude as Bounded (Bounded (..))+import qualified Prelude as Num (Integral (..), Num (..), (+), (^))++---++class (Num.Integral a, Show a) => GenIntegral a+ where+ -- | Generators for 'Integer', 'Natural', 'Positive',+ -- or 'Signed' selected from one of three methods:+ --+ -- * small numbers (magnitude less than ten)+ -- * large numbers (well in excess of 64-bit)+ -- * numbers at or around a bound of 'Int' or 'Word'+ integral :: Hedgehog.Gen a++instance GenIntegral Integer where integral = integer+instance GenIntegral Natural where integral = boundedBelow+instance GenIntegral Positive where integral = boundedBelow+instance GenIntegral Signed where integral = signed++---++class (Num.Integral a, Bounded.Bounded a, Show a) => GenFinite a+ where+ finite :: Hedgehog.Gen a++instance GenFinite Int where finite = defaultFinite++instance GenFinite Word where finite = defaultFinite++defaultFinite :: (Num.Integral a, Bounded.Bounded a) => Hedgehog.Gen a+defaultFinite = Gen.choice+ [ Gen.integral $ Range.linear Bounded.minBound Bounded.maxBound+ , Gen.integral $ Range.linear Bounded.maxBound Bounded.minBound+ ]++---++smol :: Num.Integral a => a+smol = 10++astronomical :: Num.Integral a => a+astronomical = 2 Num.^ (99 :: Integer)++bigRange :: Num.Integral a => Range.Range a+bigRange = Range.exponential smol astronomical++---++integer :: Hedgehog.Gen Integer+integer = Gen.choice [smolInteger, nearFiniteBoundInteger, bigInteger]++smolInteger :: Hedgehog.Gen Integer+smolInteger = Gen.integral $ Range.linearFrom 0 (Num.negate smol) smol++bigInteger :: Hedgehog.Gen Integer+bigInteger = Gen.element [id, Num.negate] <*> Gen.integral bigRange++nearFiniteBoundInteger :: Hedgehog.Gen Integer+nearFiniteBoundInteger = Gen.element [id, Num.negate] <*> nearPositiveFiniteBound++---++boundedBelow :: forall a. (BoundedBelow a, Num.Integral a) => Hedgehog.Gen a+boundedBelow = Gen.choice [smolBoundedBelow, nearPositiveFiniteBound, bigBoundedBelow]++smolBoundedBelow :: forall a. (BoundedBelow a, Num.Integral a) => Hedgehog.Gen a+smolBoundedBelow = fmap Num.fromInteger $ Gen.integral $ Range.linear (Num.toInteger $ minBound @a) smol++bigBoundedBelow :: forall a. (BoundedBelow a, Num.Integral a) => Hedgehog.Gen a+bigBoundedBelow = fmap Num.fromInteger $ Gen.integral bigRange++nearPositiveFiniteBound :: forall a. Num.Integral a => Hedgehog.Gen a+nearPositiveFiniteBound = fmap Num.fromInteger $+ pure (Num.+)+ <*> Gen.element+ [ Num.toInteger (Bounded.maxBound :: Int)+ , Num.toInteger (Bounded.maxBound :: Word)+ ]+ <*> smolInteger++---++signed :: Hedgehog.Gen Signed+signed = Gen.choice [smolSigned, nearFiniteBoundSigned, bigSigned]++smolSigned :: Hedgehog.Gen Signed+smolSigned = Gen.frequency+ [ (,) 1 $ pure Zero+ , (,) 9 $ pure NonZero <*> sign <*> smolBoundedBelow+ ]++bigSigned :: Hedgehog.Gen Signed+bigSigned = pure NonZero <*> sign <*> bigBoundedBelow++nearFiniteBoundSigned :: Hedgehog.Gen Signed+nearFiniteBoundSigned = pure NonZero <*> sign <*> nearPositiveFiniteBound++---++sign :: Hedgehog.Gen Sign+sign = Gen.element [PlusSign, MinusSign]
+ test/Main.hs view
@@ -0,0 +1,277 @@+module Main (main) where++import Integer++import Essentials++import Test.Hspec (hspec, describe, it, shouldBe)+import Test.Hspec.Hedgehog+ ((===), evalMaybe, modifyMaxSuccess, hedgehog)++import Control.DeepSeq (NFData, ($!!))+import Control.Exception (Exception, throw)+import Data.Either (Either (..))+import Data.Int (Int)+import Data.List (take)+import Data.Word (Word)+import Integer.Gen (GenFinite)+import Integer.Gen (GenIntegral)+import Prelude (Num, fromInteger, toInteger, ($!), (*), (+), (-))+import System.IO (IO)++import qualified Control.Exception as Exception (ArithException (Underflow))+import qualified Control.Monad.Catch as Exception (MonadCatch, try)+import qualified Data.Bool as Bool+import qualified Data.Either as Either+import qualified Data.Ord as Ord+import qualified Hedgehog+import qualified Integer.Gen as Gen+import qualified Prelude as Bounded (Bounded (..))+import qualified Prelude as Num (fromInteger)+import qualified Prelude as Num (toInteger)++main :: IO ()+main = hspec do++ describe "Closed Num operations op behaves the same in A \+ \as in Integer" $ modifyMaxSuccess (\_ -> 1000) do++ let check :: forall a m. GenIntegral a => Monad m =>+ (forall b. Num b => b -> b -> b) -> Hedgehog.PropertyT m ()+ check o = do+ x :: a <- Hedgehog.forAll Gen.integral+ y :: a <- Hedgehog.forAll Gen.integral+ x `o` y === fromInteger (toInteger x `o` toInteger y)++ it "op = (+), A = Positive" $ hedgehog $ check @Positive (+)+ it "op = (+), A = Signed" $ hedgehog $ check @Signed (+)+ it "op = (*), A = Positive" $ hedgehog $ check @Positive (*)+ it "op = (*), A = Signed" $ hedgehog $ check @Signed (*)++ describe "subtract in A behaves the same as \+ \(-) in B" $ modifyMaxSuccess (\_ -> 1000) do++ let check :: forall a b m.+ (GenIntegral a, Subtraction a, Subtraction' b, Num b) =>+ (IntegerConvert a b, IntegerNarrow b a) =>+ (Eq b, Show b) =>+ Exception.MonadCatch m => Hedgehog.PropertyT m ()+ check = do+ x :: a <- Hedgehog.forAll Gen.integral+ y :: a <- Hedgehog.forAll Gen.integral+ (subtract x y :: b) === (convert x - convert y :: b)++ it "A = Natural, B = Signed" $ hedgehog $ check @Natural @Signed+ it "A = Natural, B = Integer" $ hedgehog $ check @Natural @Integer+ it "A = Positive, B = Signed" $ hedgehog $ check @Positive @Signed+ it "A = Positive, B = Integer" $ hedgehog $ check @Positive @Integer++ describe "(-) in A behaves the same as (-) in Integer if the result \+ \is in A, undefined otherwise" $ modifyMaxSuccess (\_ -> 1000) do++ let check :: forall a m.+ (GenIntegral a, Subtraction a, IntegerNarrow Integer a) =>+ Exception.MonadCatch m => Hedgehog.PropertyT m ()+ check = do+ x :: a <- Hedgehog.forAll Gen.integral+ y :: a <- Hedgehog.forAll Gen.integral+ case narrow (toInteger x - toInteger y) :: Maybe a of+ Just z -> x - y === z+ Nothing -> do+ z <- Exception.try (pure $! x - y)+ z === Either.Left Exception.Underflow++ it "A = Positive" $ hedgehog $ check @Positive++ describe "convert (convert x) = x" do++ let check :: forall a b m. (GenIntegral a, IntegerEquiv a b) =>+ Monad m => Hedgehog.PropertyT m ()+ check = do+ x :: a <- Hedgehog.forAll Gen.integral+ convert (convert x :: b) === x++ it "A = Integer, B = Signed" $ hedgehog $ check @Integer @Signed+ it "A = Signed, B = Integer" $ hedgehog $ check @Signed @Integer++ describe "narrow (convert x) = Just x" $ modifyMaxSuccess (\_ -> 1000) do++ let check :: forall a b m.+ (GenIntegral a, IntegerConvert a b, IntegerNarrow b a) =>+ Monad m => Hedgehog.PropertyT m ()+ check = do+ x :: a <- Hedgehog.forAll Gen.integral+ narrow (convert x :: b) === Just x++ it "A = Natural, B = Integer" $ hedgehog $ check @Natural @Integer+ it "A = Natural, B = Signed" $ hedgehog $ check @Natural @Signed+ it "A = Positive, B = Integer" $ hedgehog $ check @Positive @Integer+ it "A = Positive, B = Signed" $ hedgehog $ check @Positive @Signed+ it "A = Positive, B = Natural" $ hedgehog $ check @Positive @Natural++ describe "narrow x = (Just y | convert y = x) \+ \or Nothing" $ modifyMaxSuccess (\_ -> 1000) do++ let check :: forall a b m. (GenIntegral a, BoundedBelow b) =>+ (IntegerConvert b a, IntegerNarrow a b) =>+ (Show b, Eq b) => Monad m => Hedgehog.PropertyT m ()+ check = do+ x :: a <- Hedgehog.forAll Gen.integral+ let y :: Maybe b = narrow x+ if x Ord.>= convert (minBound @b)+ then do+ z <- evalMaybe y+ convert z === x+ else y === Nothing++ it "A = Integer, B = Natural" $ hedgehog $ check @Integer @Natural+ it "A = Signed, B = Natural" $ hedgehog $ check @Signed @Natural+ it "A = Integer, B = Positive" $ hedgehog $ check @Integer @Positive+ it "A = Signed, B = Positive" $ hedgehog $ check @Signed @Positive+ it "A = Natural, B = Positive" $ hedgehog $ check @Natural @Positive++ describe "yolo (yolo x) = x, if Integer x is in range of A" do++ let check :: forall a m. (GenIntegral a, BoundedBelow a) =>+ Exception.MonadCatch m => Hedgehog.PropertyT m ()+ check = do+ x :: Integer <- Hedgehog.forAll Gen.integral+ let y :: a = yolo x+ if x Ord.>= Num.toInteger (minBound @a)+ then yolo y === x+ else do+ z <- Exception.try (pure $! y)+ z === Either.Left Exception.Underflow++ it "A = Positive" $ hedgehog $ check @Positive+ it "A = Natural " $ hedgehog $ check @Natural++ describe "toFinite x = (Just y | fromInteger y = x) \+ \or Nothing" $ modifyMaxSuccess (\_ -> 1000) do++ let check :: forall a b m. Monad m =>+ (ConvertWithFinite a, GenIntegral a, Show a) =>+ (Integer.Finite b, Eq b, Show b) =>+ Hedgehog.PropertyT m ()+ check = do+ x :: a <- Hedgehog.forAll Gen.integral+ let x' = Num.toInteger x+ let ok = x' Ord.>= Num.toInteger (Bounded.minBound :: b) Bool.&&+ x' Ord.<= Num.toInteger (Bounded.maxBound :: b)+ (Integer.toFinite x :: Maybe b) ===+ if ok then Just (Num.fromInteger x') else Nothing++ it "A = Integer, B = Int " $ hedgehog $ check @Integer @Int+ it "A = Integer, B = Word" $ hedgehog $ check @Integer @Word+ it "A = Natural, B = Int " $ hedgehog $ check @Natural @Int+ it "A = Natural, B = Word" $ hedgehog $ check @Natural @Word+ it "A = Positive, B = Int " $ hedgehog $ check @Positive @Int+ it "A = Positive, B = Word" $ hedgehog $ check @Positive @Word+ it "A = Signed, B = Int " $ hedgehog $ check @Signed @Int+ it "A = Signed, B = Word" $ hedgehog $ check @Signed @Word++ describe "fromFinite x = narrow (toInteger x)" do++ let check :: forall a b m. Monad m =>+ (ConvertWithFinite a, IntegerNarrow Integer a, Eq a, Show a) =>+ (Finite b, GenFinite b, Show b) =>+ Hedgehog.PropertyT m ()+ check = do+ x :: b <- Hedgehog.forAll Gen.finite+ (Integer.fromFinite x :: Maybe a) === Integer.narrow (Num.toInteger x)++ it "A = Int, B = Integer " $ hedgehog $ check @Integer @Int+ it "A = Word, B = Integer" $ hedgehog $ check @Integer @Word+ it "A = Int, B = Natural " $ hedgehog $ check @Natural @Int+ it "A = Word, B = Natural" $ hedgehog $ check @Natural @Word+ it "A = Int, B = Positive " $ hedgehog $ check @Positive @Int+ it "A = Word, B = Positive" $ hedgehog $ check @Positive @Word+ it "A = Int, B = Signed " $ hedgehog $ check @Signed @Int+ it "A = Word, B = Signed" $ hedgehog $ check @Signed @Word++ describe "Enum @Positive" $ do++ describe "[a ..]" $ do+ it "counts upward" $+ take 3 [5 :: Positive ..] `shouldBe` [5, 6, 7]+ it "can start with 1" $+ take 3 [1 :: Positive ..] `shouldBe` [1, 2, 3]++ describe "[a .. b]" $ do+ it "counts upward" $+ [5 .. 8 :: Positive] `shouldBe` [5, 6, 7, 8]+ it "can start with 1" $+ [1 .. 5 :: Positive] `shouldBe` [1, 2, 3, 4, 5]+ it "does not count downward" $ do+ [8 .. 5 :: Positive] `shouldBe` []+ [8 .. 7 :: Positive] `shouldBe` []+ it "can return 1 item" $ do+ [3 .. 3 :: Positive] `shouldBe` [3]+ [1 .. 1 :: Positive] `shouldBe` [1]++ describe "[a, b ..]" $ do+ it "can count upward by 1" $ do+ take 5 [5, 6 :: Positive ..] `shouldBe` [5, 6, 7, 8, 9]+ take 5 [1, 2 :: Positive ..] `shouldBe` [1, 2, 3, 4, 5]+ it "can count downward by 1" $+ [5, 4 :: Positive ..] `shouldBe` [5, 4, 3, 2, 1]+ it "can count upward by 2" $ do+ take 5 [5, 7 :: Positive ..] `shouldBe` [5, 7, 9, 11, 13]+ take 5 [1, 3 :: Positive ..] `shouldBe` [1, 3, 5, 7, 9]+ it "can count downward by 2" $+ [9, 7 :: Positive ..] `shouldBe` [9, 7, 5, 3, 1]+ it "can count downward by 2 without exactly reaching its lower bound" $+ [8, 6 :: Positive ..] `shouldBe` [8, 6, 4, 2]+ it "can repeat 1 item indefinitely" $+ take 5 [4, 4 :: Positive ..] `shouldBe` [4, 4, 4, 4, 4]++ describe "[a, b .. c]" $ do+ it "can count upward by 1" $ do+ [5, 6 .. 9 :: Positive] `shouldBe` [5, 6, 7, 8, 9]+ [1, 2 .. 5 :: Positive] `shouldBe` [1, 2, 3, 4, 5]+ it "can count downward by 1" $+ [9, 8 .. 5 :: Positive] `shouldBe` [9, 8, 7, 6, 5]+ it "can count upward by 2" $ do+ [5, 7 .. 11 :: Positive] `shouldBe` [5, 7, 9, 11]+ [1, 3 .. 7 :: Positive] `shouldBe` [1, 3, 5, 7]+ it "can count upward without exactly reaching its upper bound" $+ [5, 7 .. 12 :: Positive] `shouldBe` [5, 7, 9, 11]+ it "can count downward by 2" $+ [11, 9 .. 5 :: Positive] `shouldBe` [11, 9, 7, 5]+ it "can count downward by 2 without exactly reaching its lower bound" $+ [11, 9 .. 4 :: Positive] `shouldBe` [11, 9, 7, 5]+ it "can count downward with a lower bound of 1" $ do+ [7, 5 .. 1 :: Positive] `shouldBe` [7, 5, 3, 1]+ [8, 6 .. 1 :: Positive] `shouldBe` [8, 6, 4, 2]+ it "can repeat 1 item indefinitely" $ do+ take 5 [4, 4 .. 9 :: Positive] `shouldBe` [4, 4, 4, 4, 4]+ take 5 [4, 4 .. 4 :: Positive] `shouldBe` [4, 4, 4, 4, 4]+ it "can return 1 item" $ do+ [4, 5 .. 4 :: Positive] `shouldBe` [4]+ [4, 3 .. 4 :: Positive] `shouldBe` [4]+ it "can return an empty list" $ do+ [4, 4 .. 3 :: Positive] `shouldBe` []+ [4, 5 .. 3 :: Positive] `shouldBe` []+ [5, 4 .. 6 :: Positive] `shouldBe` []++ describe "deepseq @Signed" $ do+ it "can succeed" $ do+ x <- force (NonZero MinusSign 5)+ x `shouldBe` Right (-5)+ it "can force an error" $ do+ x <- force (throw X :: Signed)+ x `shouldBe` Left X+ it "can force an error in sign" $ do+ x <- force (NonZero (throw X) 5)+ x `shouldBe` Left X+ it "can force an error in magnitude" $ do+ x <- force (NonZero MinusSign (throw X))+ x `shouldBe` Left X++data X = X+ deriving (Eq, Show)++instance Exception X++force :: NFData a => Exception.MonadCatch m => a -> m (Either X a)+force x = Exception.try (pure $!! x)