packages feed

integer-types (empty) → 0.0.0.0

raw patch · 21 files changed

+1590/−0 lines, 21 filesdep +basedep +deepseqdep +exceptions

Dependencies added: base, deepseq, exceptions, hedgehog, hspec, integer-types

Files

+ changelog.md view
@@ -0,0 +1,3 @@+# 0.0.0.0 (2022-11-29)++* Initial release
+ integer-generators/Integer/Gen.hs view
@@ -0,0 +1,122 @@+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
@@ -0,0 +1,109 @@+cabal-version: 3.0++name: integer-types+version: 0.0.0.0++category: Numeric+synopsis: Integer, Natural, and Positive++description:+    The base package contains two unbounded integral types:+    Integer (-∞, ∞) and Natural (0, ∞). This package expands that+    integral repertoire with the addition of Positive (1, ∞).++author: Chris Martin+maintainer: Chris Martin, Julie Moronuki++homepage: https://github.com/typeclasses/integer-types+bug-reports: https://github.com/typeclasses/integer-types/issues++license: Apache-2.0+license-file: license.txt++extra-doc-files: readme.md changelog.md++common base+    default-language: GHC2021+    ghc-options: -Wall+    default-extensions:+        MultiParamTypeClasses+        NoGeneralizedNewtypeDeriving+        NoImplicitPrelude+        PatternSynonyms+        ViewPatterns+    build-depends:+        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++library+    import: base+    hs-source-dirs: integer-types+    exposed-modules:+        Integer+        Integer.BoundedBelow+        Integer.Conversion+        Integer.Finite+        Integer.Integer+        Integer.Natural+        Integer.Positive+        Integer.Sign+        Integer.Signed+        Integer.Subtraction+    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+    type: exitcode-stdio-1.0+    main-is: Main.hs+    hs-source-dirs: test-integer-finite+    build-depends: integer-generators
+ integer-types/Integer.hs view
@@ -0,0 +1,24 @@+{-# 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 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++
+ integer-types/Integer/Conversion.hs view
@@ -0,0 +1,93 @@+{-# 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 view
@@ -0,0 +1,59 @@+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 view
@@ -0,0 +1,65 @@+{-# 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 view
@@ -0,0 +1,86 @@+{-# 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 view
@@ -0,0 +1,75 @@+{-# 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 view
@@ -0,0 +1,160 @@+{-# 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 view
@@ -0,0 +1,24 @@+{-# 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 view
@@ -0,0 +1,213 @@+{-# 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 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
+ license.txt view
@@ -0,0 +1,13 @@+Copyright 2022 Mission Valley Software LLC++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++    http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.
+ readme.md view
@@ -0,0 +1,135 @@+## Core types: Integer, Natural, Positive++The primary module of the `integer-types` package is `Integer`, which exports+the following integer-like types:++Type          | Range+--------------|------------+`Integer`     | (-∞, ∞)+`Natural`     | (0, ∞)+`Positive`    | (1, ∞)++## The Signed type++In addition to `Integer`, there is also an equivalent type called `Signed` that+is represented as:++```haskell+data Signed = Zero | NonZero Sign Positive++data Sign = MinusSign | PlusSign+```++`Signed` also comes with bundled pattern synonyms that allow it to be used as if+it had the following definition:++```haskell+data Signed = Minus Positive | Zero | Plus Positive+```++## Monomorphic conversions++The following modules contain monomorphic conversion functions:++- `Integer.Integer`+- `Integer.Natural`+- `Integer.Positive`+- `Integer.Signed`++For example, you can convert from `Positive` to `Integer` using either+`Integer.Positive.toInteger` or `Integer.Integer.fromPositive`, which are two+names for the same function of type `Positive -> Integer`.++Since not all integers are positive, the corresponding function in the reverse+direction has a `Maybe` codomain. `Integer.Integer.toPositive` and+`Integer.Positive.fromInteger` have the type `Integer -> Maybe Positive`.++## Polymorphic conversions++The `Integer` module exports two polymorphic conversion functions. The first is+for conversions that always succeed, such as `Positive -> Integer`.++```haskell+convert :: IntegerConvert a b => a -> b+```++The second is for conversions that may fail because they convert to a subset of+the domain, such as `Integer -> Maybe Positive`.++```haskell+narrow :: IntegerNarrow a b => a -> Maybe b+```++## Finite integer subsets++In addition to the conversion utilities discussed above, this library also+provides some minimal support for converting to/from the `Word` and `Int` types.+These are system-dependent finite subsets of `Integer` that are sometimes used+for performance reasons.++```haskell+toFinite   :: (ConvertWithFinite a, Finite b) => a -> Maybe b+fromFinite :: (ConvertWithFinite a, Finite b) => b -> Maybe a+```++For example, `toFinite` may specialize as `Positive -> Maybe Int`, and+`fromFinite` may specialize as `Int -> Maybe Positive`.++## Monomorphic subtraction++For the `Integer` and `Signed` types that represent the full range of integers,+the standard arithmetic operations in the `Num` and `Integral` classes are+suitable.++For `Natural` and `Positive`, which are subsets of the integers, the standard+classes are not entirely appropriate. Consider, for example, subtraction.++```haskell+(-) :: Num a => a -> a -> a+```++`Natural` and `Positive` do belong to the `Num` class, but subtraction and some+other operations are partial; the expression `1 - 2` throws instead of returning+a value, because the integer result `-1` is negative and not representable by+either `Natural` or `Positive`.++For this reason, `Natural` and `Positive` have their own subtraction functions+that return `Signed`.++```haskell+-- from Integer.Positive+subtract :: Positive -> Positive -> Signed++-- from Integer.Natural+subtract :: Natural -> Natural -> Signed+```++## Polymorphic subtraction++In addition to the `(-)` method from the `Num` class and the `subtract`+functions for `Natural` and `Positive`, there are some polymorphic subtraction+functions in the `Integer` module. `subtractSigned` generalizes the two+monomorphic functions discussed in the previous section. Its codomain is+`Signed`.++```haskell+subtractSigned :: forall a. Subtraction a =>+    a -> a -> Signed+```++`subtractInteger` does the same thing, but gives the result as `Integer` instead+of `Signed`.++```haskell+subtractInteger :: forall a. Subtraction a =>+    a -> a -> Integer+```++The `subtract` function generalizes further. Its domain is any subtractable type+(`Natural`, `Positive`, `Integer`, or `Signed`) and its codomain is any type+that can represent the full range of integers (`Integer` or `Signed`).++```haskell+subtract :: forall b a. (Subtraction' b, Subtraction a) =>+    a -> a -> b+```
+ test-integer-arithmetic/Main.hs view
@@ -0,0 +1,78 @@+{-# 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 view
@@ -0,0 +1,91 @@+{-# 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 view
@@ -0,0 +1,40 @@+{-# 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 view
@@ -0,0 +1,71 @@+{-# 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 view
@@ -0,0 +1,71 @@+{-# 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