integer-types 0.1.1.0 → 0.1.2.0
raw patch · 15 files changed
+850/−682 lines, 15 files
Files
- changelog.md +4/−0
- integer-types.cabal +4/−2
- library/Integer.hs +36/−13
- library/Integer/BoundedBelow.hs +2/−4
- library/Integer/Conversion.hs +61/−46
- library/Integer/Finite.hs +32/−34
- library/Integer/Integer.hs +39/−23
- library/Integer/Natural.hs +50/−28
- library/Integer/Positive.hs +46/−24
- library/Integer/Positive/Unsafe.hs +106/−74
- library/Integer/Sign.hs +13/−12
- library/Integer/Signed.hs +130/−121
- library/Integer/Subtraction.hs +18/−20
- test/Integer/Gen.hs +47/−40
- test/Main.hs +262/−241
changelog.md view
@@ -1,3 +1,7 @@+## 0.1.2.0 (2023-06-26)++Add `Read` instance for `Positive`+ ## 0.1.1.0 (2023-04-22) Add `Hashable` instances for `Positive`, `Sign`, and `Signed`
integer-types.cabal view
@@ -1,7 +1,7 @@ cabal-version: 3.0 name: integer-types-version: 0.1.1.0+version: 0.1.2.0 category: Numeric synopsis: Integer, Natural, and Positive@@ -26,7 +26,9 @@ default-language: GHC2021 ghc-options: -Wall default-extensions:+ BlockArguments DerivingStrategies+ LambdaCase NoImplicitPrelude PatternSynonyms ViewPatterns@@ -64,7 +66,7 @@ , exceptions ^>= 0.10.4 , integer-types , hedgehog ^>= 1.0.5 || ^>= 1.1 || ^>= 1.2- , hspec ^>= 2.8.5 || ^>= 2.9 || ^>= 2.10+ , hspec ^>= 2.8.5 || ^>= 2.9 || ^>= 2.10 || ^>= 2.11 , hspec-hedgehog ^>= 0.0.1 main-is: Main.hs other-modules:
library/Integer.hs view
@@ -1,22 +1,45 @@ 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),+ ( -- ** 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+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.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))+import Integer.Subtraction+ ( Subtraction (subtractInteger, subtractSigned),+ Subtraction' (subtract),+ )
library/Integer/BoundedBelow.hs view
@@ -3,9 +3,7 @@ import Numeric.Natural (Natural) class BoundedBelow a where- minBound :: a+ minBound :: a instance BoundedBelow Natural where- minBound = 0--+ minBound = 0
library/Integer/Conversion.hs view
@@ -1,84 +1,100 @@ module Integer.Conversion- (- IntegerNarrow (narrow),+ ( IntegerNarrow (narrow), IntegerConvert (convert), IntegerEquiv, yolo, )- where+where import Essentials- import Integer.Integer (Integer)+import Integer.Integer qualified as Integer import Integer.Natural (Natural)+import Integer.Natural qualified as Natural import Integer.Positive (Positive)+import Integer.Positive qualified as 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 (..))+import Integer.Signed qualified as Signed+import Prelude qualified as Num (Integral (..), Num (..)) class IntegerNarrow a b => IntegerConvert a b where- convert :: a -> b+ convert :: a -> b class IntegerNarrow a b where- narrow :: a -> Maybe b+ 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 Integer Integer -instance IntegerEquiv Natural Natural-instance IntegerConvert Natural Natural where convert = id-instance IntegerNarrow Natural Natural where narrow = Just+instance IntegerConvert Integer Integer where convert = id -instance IntegerEquiv Positive Positive+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 IntegerNarrow Positive Positive 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 Signed -instance IntegerEquiv Signed Integer-instance IntegerConvert Signed Integer where convert = Signed.toInteger-instance IntegerNarrow Signed Integer where narrow = Just . convert+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 Integer Natural where narrow = Integer.toNatural -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 Natural Integer where narrow = Just . convert -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 IntegerConvert Natural Integer where convert = Natural.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 Natural where narrow = Signed.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+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'@@ -86,6 +102,5 @@ -- @ -- yolo = 'Num.fromInteger' . 'Num.toInteger' -- @--- yolo :: (Num.Integral a, Num.Num b) => a -> b yolo = Num.fromInteger . Num.toInteger
library/Integer/Finite.hs view
@@ -1,59 +1,57 @@ module Integer.Finite where -import Essentials- import Data.Int (Int)+import Data.Maybe qualified as Maybe import Data.Word (Word)+import Essentials import Integer.Integer (Integer)+import Integer.Integer qualified as Integer import Integer.Natural (Natural)+import Integer.Natural qualified as Natural import Integer.Positive (Positive)+import Integer.Positive qualified as Positive import Integer.Signed (Signed)+import Integer.Signed qualified as 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+ 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+ 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+ 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+ 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+ 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+ toFinite :: ConvertWithFinite a => a -> Maybe b+ fromFinite :: ConvertWithFinite a => b -> Maybe a instance Finite Int where- toFinite = toInt- fromFinite = fromInt+ toFinite = toInt+ fromFinite = fromInt instance Finite Word where- toFinite = toWord- fromFinite = fromWord+ toFinite = toWord+ fromFinite = fromWord
library/Integer/Integer.hs view
@@ -1,31 +1,45 @@ module Integer.Integer- (- {- * Type -} Integer,- {- * Conversion -}- {- ** Positive -} toPositive, fromPositive,- {- ** Natural -} toNatural, fromNatural,- {- ** Signed -} toSigned, fromSigned,- {- ** Int -} toInt, fromInt,- {- ** Word -} toWord, fromWord,- )- where+ ( -- * Type+ Integer, -import Essentials+ -- * Conversion + -- ** Positive+ toPositive,+ fromPositive,++ -- ** Natural+ toNatural,+ fromNatural,++ -- ** Signed+ toSigned,+ fromSigned,++ -- ** Int+ toInt,+ fromInt,++ -- ** Word+ toWord,+ fromWord,+ )+where++import Data.Bool qualified as Bool import Data.Int (Int)+import Data.Ord qualified as Ord import Data.Word (Word)+import Essentials+import Integer.Natural qualified as Natural import Integer.Positive (Positive)+import Integer.Positive qualified as Positive import Integer.Signed (Signed (..))+import Integer.Signed qualified as 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 (..))+import Prelude qualified as Bounded (Bounded (..))+import Prelude qualified as Num (Integral (..), Num (..)) toPositive :: Integer -> Maybe Positive toPositive = Positive.fromInteger@@ -48,8 +62,9 @@ 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)+ ok =+ x Ord.>= Num.toInteger (Bounded.minBound :: Int)+ Bool.&& x Ord.<= Num.toInteger (Bounded.maxBound :: Int) fromInt :: Int -> Integer fromInt = Num.toInteger@@ -57,8 +72,9 @@ 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)+ 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
@@ -1,34 +1,56 @@ 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,- {- * List -} length,- )- where+ ( -- * Type+ Natural, -import Essentials+ -- * Subtraction+ subtract, + -- * Conversion++ -- ** Positive+ toPositive,+ fromPositive,++ -- ** Integer+ toInteger,+ fromInteger,++ -- ** Signed+ toSigned,+ fromSigned,++ -- ** Int+ toInt,+ fromInt,++ -- ** Word+ toWord,+ fromWord,++ -- * One (1)+ one,+ addOne,+ subtractOne,++ -- * List+ length,+ )+where+ import Data.Int (Int)+import Data.List qualified as List+import Data.Ord qualified as Ord import Data.Word (Word)+import Essentials+import Integer.Positive qualified as Positive+import Integer.Positive.Unsafe (Positive)+import Integer.Positive.Unsafe qualified as Positive.Unsafe import Integer.Signed (Signed (..))+import Integer.Signed qualified as Signed import Numeric.Natural (Natural)-import Integer.Positive.Unsafe (Positive) import Prelude (Integer)--import qualified Data.List as List-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 (..))+import Prelude qualified as Bounded (Bounded (..))+import Prelude qualified as Num (Integral (..), Num (..)) toPositive :: Natural -> Maybe Positive toPositive = Positive.fromNatural@@ -71,9 +93,9 @@ 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+ 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@@ -83,8 +105,8 @@ subtractOne :: Natural -> Maybe Signed subtractOne x = case x of- 0 -> Nothing- p -> Just (subtract p 1)+ 0 -> Nothing+ p -> Just (subtract p 1) length :: [a] -> Natural length = List.foldl' (\x _ -> x Num.+ 1) 0
library/Integer/Positive.hs view
@@ -1,33 +1,55 @@ 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,- {- * List -} length,- )- where+ ( -- * Type+ Positive, -import Essentials+ -- * Subtraction+ subtract, + -- * Conversion++ -- ** Natural+ toNatural,+ fromNatural,++ -- ** Integer+ toInteger,+ fromInteger,++ -- ** Signed+ toSigned,+ fromSigned,++ -- ** Int+ toInt,+ fromInt,++ -- ** Word+ toWord,+ fromWord,++ -- * One (1)+ one,+ addOne,+ subtractOne,++ -- * List+ length,+ )+where+ import Data.Int (Int)+import Data.List qualified as List import Data.List.NonEmpty (NonEmpty (..))+import Data.Ord qualified as Ord import Data.Word (Word)+import Essentials import Integer.Positive.Unsafe (Positive, addOne, one, toInteger, toNatural)+import Integer.Positive.Unsafe qualified as Unsafe import Integer.Signed (Signed (..)) import Numeric.Natural (Natural) import Prelude (Integer)--import qualified Data.List as List-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 (..))+import Prelude qualified as Bounded (Bounded (..))+import Prelude qualified as Num (Integral (..), Num (..)) fromInteger :: Integer -> Maybe Positive fromInteger x = if x Ord.> 0 then Just (Unsafe.fromInteger x) else Nothing@@ -61,9 +83,9 @@ 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+ 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@@ -73,7 +95,7 @@ fromSigned :: Signed -> Maybe Positive fromSigned (Plus x) = Just x-fromSigned _ = Nothing+fromSigned _ = Nothing length :: NonEmpty a -> Positive length (_ :| xs) = List.foldl' (\x _ -> x Num.+ 1) 1 xs
library/Integer/Positive/Unsafe.hs view
@@ -1,42 +1,66 @@-{- | 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'. -}-+-- | 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+ ( -- * Type+ Positive (FromNatural), -import Essentials ( ($), Enum, Eq, Ord, Show, (.), id )+ -- * Conversion + -- ** Natural+ toNatural,+ fromNatural,+ fromNaturalChecked,++ -- ** Integer+ toInteger,+ fromInteger,+ fromIntegerChecked,++ -- ** Int+ toInt,+ fromInt,+ fromIntChecked,++ -- * Arithmetic+ subtract,+ subtractChecked,++ -- * One (1)+ one,+ addOne,+ subtractOne,+ subtractOneChecked,+ )+where++import Control.DeepSeq qualified as DeepSeq+import Control.Exception qualified as Exception+import Control.Monad.Fail (fail)+import Data.Bits qualified as Bits import Data.Hashable (Hashable)+import Data.List qualified as List+import Data.Maybe qualified as Maybe+import Data.Ord qualified as Ord+import Essentials import Integer.BoundedBelow (BoundedBelow)+import Integer.BoundedBelow qualified as 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+import Text.Read qualified as Read+import Text.Show qualified as Show+import Prelude (Int, Integer, Integral, Num, Read, Real)+import Prelude qualified as Enum (Enum (..))+import Prelude qualified as Num+ ( Integral (..),+ Num (..),+ Real (..),+ fromIntegral,+ ) -newtype Positive = FromNatural{ toNatural :: Natural }- deriving newtype (Eq, Ord, Hashable)+newtype Positive = FromNatural {toNatural :: Natural}+ deriving newtype (Eq, Ord, Hashable) instance DeepSeq.NFData Positive where rnf (FromNatural x) = DeepSeq.rnf x @@ -77,7 +101,7 @@ subtractOne = fromNatural . (Num.- 1) . toNatural subtractOneChecked :: Positive -> Positive-subtractOneChecked x = case x of { 1 -> Exception.throw Exception.Underflow; _ -> subtractOne x }+subtractOneChecked x = case x of 1 -> Exception.throw Exception.Underflow; _ -> subtractOne x toInt :: Positive -> Int toInt = Num.fromIntegral . toNatural@@ -89,7 +113,7 @@ fromInt = fromNatural . Num.fromIntegral fromIntChecked :: Int -> Positive-fromIntChecked x = case Num.signum x of { 1 -> fromInt x; _ -> Exception.throw Exception.Underflow }+fromIntChecked x = case Num.signum x of 1 -> fromInt x; _ -> Exception.throw Exception.Underflow enumFrom :: Positive -> [Positive] enumFrom = List.map fromNatural . Enum.enumFrom . toNatural@@ -101,61 +125,69 @@ 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)+ 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)+ 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)+ let (q, r) = o (toNatural a) (toNatural b)+ in (fromNaturalChecked q, fromNaturalChecked r) -instance BoundedBelow Positive- where- minBound = 1+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 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+instance Enum Positive where+ succ = addOne+ pred = subtractOneChecked - fromEnum = toIntChecked- toEnum = fromIntChecked+ fromEnum = toIntChecked+ toEnum = fromIntChecked - enumFrom = enumFrom- enumFromTo = enumFromTo- enumFromThen = enumFromThen- enumFromThenTo = enumFromThenTo+ enumFrom = enumFrom+ enumFromTo = enumFromTo+ enumFromThen = enumFromThen+ enumFromThenTo = enumFromThenTo -instance Real Positive- where- toRational = Num.toRational . toInteger+instance Real Positive where+ toRational = Num.toRational . toInteger -instance Integral Positive- where- toInteger = toInteger- quotRem = divisionOp Num.quotRem- divMod = divisionOp Num.divMod+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+instance Show Positive where+ show = Show.show . toNatural+ showsPrec i = Show.showsPrec i . toNatural++instance Read Positive where+ readsPrec i = do+ xs <- Read.readsPrec @Natural i+ pure $ xs & Maybe.mapMaybe \case+ (0, _) -> Nothing+ (n, s) -> Just (fromNatural n, s)+ readPrec = do+ n <- Read.readPrec @Natural+ if n == 0 then fail "0" else pure $ fromNatural n
library/Integer/Sign.hs view
@@ -1,28 +1,29 @@ module Integer.Sign- (- {- * Type -} Sign (..),- {- * Operations -} negate, multiply,+ ( -- * Type+ Sign (..),++ -- * Operations+ negate,+ multiply, )- where+where +import Control.DeepSeq qualified as DeepSeq+import Data.Hashable (Hashable (hashWithSalt)) import Essentials- import Prelude (seq)-import qualified Prelude as Enum (Enum (..))-import Data.Hashable (Hashable (hashWithSalt))--import qualified Control.DeepSeq as DeepSeq+import Prelude qualified as Enum (Enum (..)) data Sign = MinusSign | PlusSign- deriving stock (Eq, Ord, Show, Enum, Bounded)+ deriving stock (Eq, Ord, Show, Enum, Bounded) instance DeepSeq.NFData Sign where rnf x = seq x () instance Hashable Sign where- hashWithSalt salt x = salt `hashWithSalt` (Enum.fromEnum x)+ hashWithSalt salt x = salt `hashWithSalt` (Enum.fromEnum x) negate :: Sign -> Sign-negate PlusSign = MinusSign+negate PlusSign = MinusSign negate MinusSign = PlusSign multiply :: Sign -> Sign -> Sign
library/Integer/Signed.hs view
@@ -1,87 +1,103 @@ 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+ ( -- * Type+ Signed (Zero, NonZero, Plus, Minus, NotPlus, NotMinus), -import Essentials+ -- * Conversion + -- ** Integer+ toInteger,+ fromInteger,++ -- ** Natural+ toNatural,+ fromNatural,++ -- ** Positive+ toPositive,+ fromPositive,++ -- ** Int+ toInt,+ fromInt,++ -- ** Word+ toWord,+ fromWord,+ )+where++import Control.DeepSeq qualified as DeepSeq import Data.Hashable (Hashable (hashWithSalt)) import Data.Int (Int)+import Data.List qualified as List+import Data.Ord qualified as Ord import Data.Word (Word)+import Essentials import Integer.Positive.Unsafe (Positive)+import Integer.Positive.Unsafe qualified as Positive.Unsafe import Integer.Sign (Sign (..))+import Integer.Sign qualified as Sign import Numeric.Natural (Natural)+import Text.Show qualified as Show 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+import Prelude qualified as Bounded (Bounded (..))+import Prelude qualified as Enum (Enum (..))+import Prelude qualified as Num (Integral (..), Num (..), Real (..)) data Signed = Zero | NonZero Sign Positive- deriving stock (Eq)+ deriving stock (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+ 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` ()+ rnf Zero = ()+ rnf (NonZero a b) = a `seq` b `seq` () instance Hashable Signed where- hashWithSalt s Zero = s `hashWithSalt` ( 0 :: Int)- hashWithSalt s (Plus x) = s `hashWithSalt` ( 1 :: Int) `hashWithSalt` x- hashWithSalt s (Minus x) = s `hashWithSalt` (-1 :: Int) `hashWithSalt` x+ hashWithSalt s Zero = s `hashWithSalt` (0 :: Int)+ hashWithSalt s (Plus x) = s `hashWithSalt` (1 :: Int) `hashWithSalt` x+ hashWithSalt s (Minus x) = s `hashWithSalt` (-1 :: Int) `hashWithSalt` x pattern Minus :: Positive -> Signed pattern Minus x = NonZero MinusSign x-pattern Plus :: Positive -> Signed +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+ 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+ where+ NotPlus = negate . fromNatural -{-# complete Zero, Minus, Plus #-}-{-# complete Plus, NotPlus #-}-{-# complete Minus, NotMinus #-}+{-# 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+toPositive _ = Nothing fromNatural :: Natural -> Signed fromNatural 0 = Zero@@ -89,129 +105,122 @@ toNatural :: Signed -> Maybe Natural toNatural (Minus _) = Nothing-toNatural Zero = Just 0-toNatural (Plus x) = Just (Positive.Unsafe.toNatural x)+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+ (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 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)+ 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+ PlusSign -> x+ MinusSign -> NonZero PlusSign p signum :: Signed -> Signed-signum Zero = Zero+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+ 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 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)+ 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+ 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+ 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)+ 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)+ 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 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+instance Enum Signed where+ pred = fromInteger . Enum.pred . toInteger+ succ = fromInteger . Enum.succ . toInteger - toEnum = fromInteger . Enum.toEnum- fromEnum = Enum.fromEnum . 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)+ 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 Real Signed where+ toRational = Num.toRational . toInteger -instance Integral Signed- where- toInteger = toInteger- quotRem = divisionOp Num.quotRem- divMod = divisionOp Num.divMod+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+instance Show Signed where+ show = Show.show . Num.toInteger+ showsPrec i = Show.showsPrec i . Num.toInteger
library/Integer/Subtraction.hs view
@@ -1,47 +1,45 @@ module Integer.Subtraction- (- Subtraction (subtractInteger, subtractSigned),+ ( Subtraction (subtractInteger, subtractSigned), Subtraction' (subtract), )- where+where import Integer.Integer (Integer) import Integer.Natural (Natural)+import Integer.Natural qualified as Natural import Integer.Positive (Positive)+import Integer.Positive qualified as 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 (..))+import Integer.Signed qualified as Signed+import Prelude qualified as Num (Num (..)) -- | Domain of a subtraction operation class Subtraction a where- subtractInteger :: a -> a -> Integer- subtractInteger a b = Signed.toInteger (subtractSigned a b)+ subtractInteger :: a -> a -> Integer+ subtractInteger a b = Signed.toInteger (subtractSigned a b) - subtractSigned :: a -> a -> Signed- subtractSigned a b = Signed.fromInteger (subtractInteger a b)+ subtractSigned :: a -> a -> Signed+ subtractSigned a b = Signed.fromInteger (subtractInteger a b) instance Subtraction Integer where- subtractInteger = (Num.-)+ subtractInteger = (Num.-) instance Subtraction Signed where- subtractInteger a b = (Num.-) (Signed.toInteger a) (Signed.toInteger b)- subtractSigned = (Num.-)+ subtractInteger a b = (Num.-) (Signed.toInteger a) (Signed.toInteger b)+ subtractSigned = (Num.-) instance Subtraction Natural where- subtractSigned = Natural.subtract+ subtractSigned = Natural.subtract instance Subtraction Positive where- subtractSigned = Positive.subtract+ subtractSigned = Positive.subtract -- | Codomain of a subtraction operation class Subtraction' b where- subtract :: Subtraction a => a -> a -> b+ subtract :: Subtraction a => a -> a -> b instance Subtraction' Integer where- subtract = subtractInteger+ subtract = subtractInteger instance Subtraction' Signed where- subtract = subtractSigned+ subtract = subtractSigned
test/Integer/Gen.hs view
@@ -1,55 +1,60 @@ module Integer.Gen- (- GenIntegral (integral),+ ( GenIntegral (integral), GenFinite (finite), astronomical, )- where--import Essentials+where 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 (..), (+), (^))+import Essentials+import Hedgehog qualified+import Hedgehog.Gen qualified as Gen+import Hedgehog.Range qualified as Range+import Integer+ ( BoundedBelow (..),+ Integer,+ Natural,+ Positive,+ Sign (..),+ Signed (..),+ )+import Prelude qualified as Bounded (Bounded (..))+import Prelude qualified 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+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 Integer where integral = integer++instance GenIntegral Natural where integral = boundedBelow+ instance GenIntegral Positive where integral = boundedBelow-instance GenIntegral Signed where integral = signed +instance GenIntegral Signed where integral = signed+ --- -class (Num.Integral a, Bounded.Bounded a, Show a) => GenFinite a- where- finite :: Hedgehog.Gen a+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+defaultFinite =+ Gen.choice+ [ Gen.integral $ Range.linear Bounded.minBound Bounded.maxBound,+ Gen.integral $ Range.linear Bounded.maxBound Bounded.minBound ] ---@@ -89,13 +94,14 @@ bigBoundedBelow = fmap Num.fromInteger $ Gen.integral bigRange nearPositiveFiniteBound :: forall a. Num.Integral a => Hedgehog.Gen a-nearPositiveFiniteBound = fmap Num.fromInteger $+nearPositiveFiniteBound =+ fmap Num.fromInteger $ pure (Num.+)- <*> Gen.element- [ Num.toInteger (Bounded.maxBound :: Int)- , Num.toInteger (Bounded.maxBound :: Word)- ]- <*> smolInteger+ <*> Gen.element+ [ Num.toInteger (Bounded.maxBound :: Int),+ Num.toInteger (Bounded.maxBound :: Word)+ ]+ <*> smolInteger --- @@ -103,9 +109,10 @@ signed = Gen.choice [smolSigned, nearFiniteBoundSigned, bigSigned] smolSigned :: Hedgehog.Gen Signed-smolSigned = Gen.frequency- [ (,) 1 $ pure Zero- , (,) 9 $ pure NonZero <*> sign <*> smolBoundedBelow+smolSigned =+ Gen.frequency+ [ (,) 1 $ pure Zero,+ (,) 9 $ pure NonZero <*> sign <*> smolBoundedBelow ] bigSigned :: Hedgehog.Gen Signed
test/Main.hs view
@@ -1,282 +1,303 @@ 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 Control.Exception qualified as Exception (ArithException (Underflow))+import Control.Monad.Catch qualified as Exception (MonadCatch, try)+import Data.Bool qualified as Bool import Data.Either (Either (..))+import Data.Either qualified as Either import Data.Int (Int) import Data.List (take) import Data.List.NonEmpty (NonEmpty ((:|)))+import Data.Ord qualified as Ord import Data.Word (Word)-import Integer.Gen (GenFinite)-import Integer.Gen (GenIntegral)-import Prelude (Num, fromInteger, toInteger, ($!), (*), (+), (-))+import Essentials+import Hedgehog qualified+import Integer+import Integer.Gen (GenFinite, GenIntegral)+import Integer.Gen qualified as Gen+import Integer.Natural qualified as Natural+import Integer.Positive qualified as Positive 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 Integer.Natural as Natural-import qualified Integer.Positive as Positive-import qualified Prelude as Bounded (Bounded (..))-import qualified Prelude as Num (fromInteger)-import qualified Prelude as Num (toInteger)+import Test.Hspec (describe, hspec, it, shouldBe)+import Test.Hspec.Hedgehog+ ( evalMaybe,+ hedgehog,+ modifyMaxSuccess,+ (===),+ )+import Prelude (Num, fromInteger, toInteger, ($!), (*), (+), (-))+import Prelude qualified as Bounded (Bounded (..))+import Prelude qualified as Num (fromInteger, 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+ 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 "A = Integer, B = Signed" $ hedgehog $ check @Integer @Signed- it "A = Signed, B = Integer" $ hedgehog $ check @Signed @Integer+ 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 "narrow (convert x) = Just x" $ modifyMaxSuccess (\_ -> 1000) do+ 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) - 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 = 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 - 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+ "(-) 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 - describe "narrow x = (Just y | convert y = x) \- \or Nothing" $ modifyMaxSuccess (\_ -> 1000) do+ it "A = Positive" $ hedgehog $ check @Positive - 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+ 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 = 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+ it "A = Integer, B = Signed" $ hedgehog $ check @Integer @Signed+ it "A = Signed, B = Integer" $ hedgehog $ check @Signed @Integer - describe "yolo (yolo x) = x, if Integer x is in range of A" do+ 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 - 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 = 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 - it "A = Positive" $ hedgehog $ check @Positive- it "A = Natural " $ hedgehog $ check @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 - describe "toFinite x = (Just y | fromInteger y = x) \- \or Nothing" $ modifyMaxSuccess (\_ -> 1000) do+ 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 - 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+ 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 = 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+ it "A = Positive" $ hedgehog $ check @Positive+ it "A = Natural " $ hedgehog $ check @Natural - describe "fromFinite x = narrow (toInteger x)" do+ 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 - 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 = 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 - 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 "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) - describe "Enum @Positive" $ do+ 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 "[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 "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 "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 ..]" $ 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 "[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+ 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 - describe "length" $ do- it "Natural" $ Natural.length "abc" `shouldBe` 3- it "Positive" $ Positive.length ('a' :| "bc") `shouldBe` 3+ describe "length" $ do+ it "Natural" $ Natural.length "abc" `shouldBe` 3+ it "Positive" $ Positive.length ('a' :| "bc") `shouldBe` 3 data X = X- deriving stock (Eq, Show)+ deriving stock (Eq, Show) instance Exception X