finitary 2.1.3.0 → 2.2.0.0
raw patch · 5 files changed
+98/−38 lines, 5 filesdep ~hedgehogdep ~hspec-hedgehogdep ~primitivePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: hedgehog, hspec-hedgehog, primitive, typelits-witnesses, vector, vector-sized
API changes (from Hackage documentation)
Files
- CHANGELOG.md +11/−0
- README.md +0/−7
- finitary.cabal +7/−8
- src/Data/Finitary.hs +16/−16
- test/Main.hs +64/−7
CHANGELOG.md view
@@ -1,5 +1,16 @@ # Revision history for finitary +## 2.2.0.0 -- 2024-08-07 + +* Fix behaviour of `previous` and `next`, which incorrectly handled endpoints. + Thanks to `blmage` for their contribution. + +* Relax upper bounds: + + - `primitive`: `< 0.8 ==> < 0.10` + - `vector`: `< 0.13 ==> < 0.14` + - `vector-sized`: `< 1.6 ==> < 1.7` + ## 2.1.3.0 -- 2024-05-09 * Add support for `finite-typelits >= 2.0.0`.
README.md view
@@ -133,13 +133,6 @@ If there's something else interesting you think can be done with this, let us know: it might make it onto this list, and into code. -## What will this work on? - -Currently, we support GHC versions ranging from 8.6 to 9.0. - -The library has been tested on x86_64, GNU/Linux and Windows. -If you have results on other platforms or architectures, please let us know too! - ## License This library is under the GNU General Public License, version 3 or later (SPDX
finitary.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: finitary -version: 2.1.3.0 +version: 2.2.0.0 synopsis: A better, more type-safe Enum. description: Provides a type class witnessing that a type has @@ -18,7 +18,6 @@ copyright: (C) Koz Ross 2019-2020 category: Data build-type: Simple -tested-with: GHC ==8.6.5 || ==8.8.3 || ==8.10.1 || == 9.0.1 extra-source-files: CHANGELOG.md README.md @@ -64,13 +63,13 @@ -DVECTOR build-depends: , primitive - ^>= 0.7.0.1 + >= 0.7.0.1 && < 0.10 , vector - ^>= 0.12.1.2 + >= 0.12.1.2 && < 0.14 , vector-sized - >= 1.4.1.0 && < 1.6 + >= 1.4.1.0 && < 1.7 , typelits-witnesses - ^>= 0.4.0.1 + >= 0.4.0.1 && < 0.5 hs-source-dirs: src ghc-options: @@ -91,11 +90,11 @@ , ghc-typelits-knownnat , ghc-typelits-natnormalise , hedgehog - >= 1.0.2 && < 1.3 + >= 1.0.2 && < 1.6 , hspec >= 2.7.1 && < 3.0 , hspec-hedgehog - >= 0.0.1.2 && < 0.2 + >= 0.0.1.2 && < 0.3 , primitive , template-haskell , typelits-witnesses
src/Data/Finitary.hs view
@@ -257,12 +257,12 @@ -- | @previous x@ gives 'Just' the inhabitant whose index precedes the index of @x@, -- or 'Nothing' if no such index exists. previous :: a -> Maybe a - previous = fmap fromFinite . guarded (/= maxBound) . dec . toFinite + previous = fmap (fromFinite . dec) . guarded (/= minBound) . toFinite -- | @next x@ gives 'Just' the inhabitant whose index follows the index of @x@, or -- 'Nothing' if no such index exists. next :: a -> Maybe a - next = fmap fromFinite . guarded (/= minBound) . inc . toFinite + next = fmap (fromFinite . inc) . guarded (/= maxBound) . toFinite class (KnownNat (GCardinality a)) => GFinitary (a :: Type -> Type) where type GCardinality a :: Nat @@ -420,9 +420,9 @@ {-# INLINE end #-} end = maxBound {-# INLINE next #-} - next = guarded (== minBound) . inc + next = fmap inc . guarded (/= maxBound) {-# INLINE previous #-} - previous = guarded (== maxBound) . dec + previous = fmap dec . guarded (/= minBound) instance Finitary Word64 where type Cardinality Word64 = $(cardinalityOf @Word64) @@ -435,9 +435,9 @@ {-# INLINE end #-} end = maxBound {-# INLINE next #-} - next = guarded (== minBound) . inc + next = fmap inc . guarded (/= maxBound) {-# INLINE previous #-} - previous = guarded (== maxBound) . dec + previous = fmap dec . guarded (/= minBound) instance Finitary Int8 where type Cardinality Int8 = $(cardinalityOf @Int8) @@ -480,9 +480,9 @@ {-# INLINE end #-} end = maxBound {-# INLINE next #-} - next = guarded (== minBound) . inc + next = fmap inc . guarded (/= maxBound) {-# INLINE previous #-} - previous = guarded (== maxBound) . dec + previous = fmap dec . guarded (/= minBound) instance Finitary Int64 where type Cardinality Int64 = $(cardinalityOf @Int64) @@ -495,9 +495,9 @@ {-# INLINE end #-} end = maxBound {-# INLINE next #-} - next = guarded (== minBound) . inc + next = fmap inc . guarded (/= maxBound) {-# INLINE previous #-} - previous = guarded (== maxBound) . dec + previous = fmap dec . guarded (/= minBound) -- Variable-width instances @@ -514,9 +514,9 @@ {-# INLINE end #-} end = maxBound {-# INLINE next #-} - next = guarded (== minBound) . inc + next = fmap inc . guarded (/= maxBound) {-# INLINE previous #-} - previous = guarded (== maxBound) . dec + previous = fmap dec . guarded (/= minBound) -- | 'Word' has a finite number of inhabitants, varying by platform. This -- instance will determine this when the library is built. @@ -531,9 +531,9 @@ {-# INLINE end #-} end = maxBound {-# INLINE next #-} - next = guarded (== minBound) . inc + next = fmap inc . guarded (/= maxBound) {-# INLINE previous #-} - previous = guarded (== maxBound) . dec + previous = fmap dec . guarded (/= minBound) -- | Since any type is isomorphic to itself, it follows that a \'valid\' @Finite -- n@ (meaning that @n@ is a 'KnownNat') has finite cardinality. @@ -548,9 +548,9 @@ {-# INLINE end #-} end = maxBound {-# INLINE next #-} - next = guarded (== minBound) . inc + next = fmap inc . guarded (/= maxBound) {-# INLINE previous #-} - previous = guarded (== maxBound) . dec + previous = fmap dec . guarded (/= minBound) -- | @Maybe a@ introduces one additional inhabitant (namely, 'Nothing') to @a@. instance (Finitary a) => Finitary (Maybe a)
test/Main.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeOperators #-} {- - Copyright (C) 2019 Koz Ross <koz.ross@retro-freedom.nz> @@ -24,24 +25,72 @@ module Main where +import Data.Bit (Bit) import Data.Finitary (Finitary (..)) -import Data.Int (Int16, Int32, Int8) +import Data.Finite (Finite) +import Data.Functor.Const (Const) +import Data.Functor.Identity (Identity) +import Data.Int (Int16, Int32, Int64, Int8) import Data.Ord (Down (..)) +import Data.Proxy (Proxy (..)) +import Data.Semigroup (All, Any, Dual, First, Last, Max, Min, Product, Sum) import qualified Data.Vector.Sized as V import qualified Data.Vector.Storable.Sized as VS import Data.Vector.Unboxed.Sized (Unbox) import qualified Data.Vector.Unboxed.Sized as VU -import Data.Word (Word16, Word32, Word8) +import Data.Word (Word16, Word32, Word64, Word8) import Foreign.Storable (Storable) import GHC.Generics (Generic) +import GHC.TypeNats (type (<=)) import Hedgehog ((===), Gen, PropertyT, forAll) import qualified Hedgehog.Gen as Gen import Hedgehog.Range (constantBounded) -import Test.Hspec (SpecWith, describe, hspec, it, parallel) +import Test.Hspec (SpecWith, describe, hspec, it, parallel, shouldBe) import Test.Hspec.Hedgehog (hedgehog, modifyMaxSize) main :: IO () main = hspec . parallel $ do + describe "Previous and next values for bounds" $ do + checkBoundsPrevNext (Proxy @All) "All" + checkBoundsPrevNext (Proxy @Any) "Any" + checkBoundsPrevNext (Proxy @Int16) "Int16" + checkBoundsPrevNext (Proxy @Int32) "Int32" + checkBoundsPrevNext (Proxy @Int64) "Int64" + checkBoundsPrevNext (Proxy @Int8) "Int8" + checkBoundsPrevNext (Proxy @Word16) "Word16" + checkBoundsPrevNext (Proxy @Word32) "Word32" + checkBoundsPrevNext (Proxy @Word64) "Word64" + checkBoundsPrevNext (Proxy @Word8) "Word8" + checkBoundsPrevNext (Proxy @Bit) "Bit" + checkBoundsPrevNext (Proxy @Ordering) "Ordering" + checkBoundsPrevNext (Proxy @()) "()" + checkBoundsPrevNext (Proxy @Bool) "Bool" + checkBoundsPrevNext (Proxy @Char) "Char" + checkBoundsPrevNext (Proxy @Int) "Int" + checkBoundsPrevNext (Proxy @Word) "Word" + checkBoundsPrevNext (Proxy @(Identity Int32)) "Identity a" + checkBoundsPrevNext (Proxy @(Down Int32)) "Down a" + checkBoundsPrevNext (Proxy @(First Int32)) "First a" + checkBoundsPrevNext (Proxy @(Last Int32)) "Last a" + checkBoundsPrevNext (Proxy @(Max Int32)) "Max a" + checkBoundsPrevNext (Proxy @(Min Int32)) "Min a" + checkBoundsPrevNext (Proxy @(Dual Int32)) "Dual a" + checkBoundsPrevNext (Proxy @(Product Int32)) "Product a" + checkBoundsPrevNext (Proxy @(Sum Int32)) "Sum a" + checkBoundsPrevNext (Proxy @(Finite 10000)) "Finite n" + checkBoundsPrevNext (Proxy @(Maybe Int32)) "Maybe a" + checkBoundsPrevNext (Proxy @(Either Bool Int32)) "Either a b" + checkBoundsPrevNext (Proxy @(Proxy Int32)) "Proxy a" + checkBoundsPrevNext (Proxy @(V.Vector 10 Int32)) "V.Vector a" + checkBoundsPrevNext (Proxy @(VS.Vector 10 Int32)) "VS.Vector a" + checkBoundsPrevNext (Proxy @(VU.Vector 10 Int32)) "VU.Vector a" + checkBoundsPrevNext (Proxy @(Bool, Int32)) "(a, b)" + checkBoundsPrevNext (Proxy @(Const Int32 Bool)) "Const a b" + checkBoundsPrevNext (Proxy @(Bool, Bool, Int32)) "(a, b, c)" + checkBoundsPrevNext (Proxy @(Bool, Int8, Bool, Int32)) "(a, b, c, d)" + checkBoundsPrevNext (Proxy @(Bool, Int8, Bool, Int8, Int32)) "(a, b, c, d, e)" + checkBoundsPrevNext (Proxy @(Bool, Int8, Bool, Int8, Bool, Int32)) "(a, b, c, d, e, f)" + checkBoundsPrevNext (Proxy @Foo) "Foo" describe "Bijectivity and order preservation" $ do checkBijection "Char" Gen.unicode checkBijection "Word8" (Gen.enumBounded @_ @Word8) @@ -76,15 +125,15 @@ . checkMonotonic "Int" $ (Gen.enumBounded @_ @Int) modifyMaxSize (const 10000) - . checkMonotonic "(Either Int Bool)" + . checkMonotonic "(Either Int32 Bool)" $ Gen.choice - [ Left <$> Gen.enumBounded @_ @Int, + [ Left <$> Gen.enumBounded @_ @Int32, Right <$> Gen.enumBounded @_ @Bool ] modifyMaxSize (const 10000) - . checkMonotonic "(Int, Bool)" + . checkMonotonic "(Int32, Bool)" $ ( (,) - <$> Gen.enumBounded @_ @Int + <$> Gen.enumBounded @_ @Int32 <*> Gen.enumBounded @_ @Bool ) modifyMaxSize (const 10000) @@ -228,3 +277,11 @@ LT -> compare dx dy === GT EQ -> compare dx dy === EQ GT -> compare dx dy === LT + +checkBoundsPrevNext :: forall a. (1 <= Cardinality a, Show a, Finitary a) => Proxy a -> String -> SpecWith () +checkBoundsPrevNext _ name = do + it ("(start :: " <> name <> ") should have no predecessor") $ + previous (start @a) `shouldBe` Nothing + it ("(end :: " <> name <> ") should have no successor") $ + next (end @a) `shouldBe` Nothing +