hashable 1.3.5.0 → 1.4.0.0
raw patch · 7 files changed
+154/−42 lines, 7 filesdep +base-orphansdep +functor-classes-compatdep +ghc-bignum-orphansdep ~basedep ~containersdep ~ghc-bignumPVP ok
version bump matches the API change (PVP)
Dependencies added: base-orphans, functor-classes-compat, ghc-bignum-orphans, transformers, transformers-compat
Dependency ranges changed: base, containers, ghc-bignum
API changes (from Hackage documentation)
+ Data.Hashable: hashedHash :: Hashed a -> Int
- Data.Hashable: class Hashable a
+ Data.Hashable: class Eq a => Hashable a
- Data.Hashable.Lifted: class Hashable1 t
+ Data.Hashable.Lifted: class Eq1 t => Hashable1 t
- Data.Hashable.Lifted: class Hashable2 t
+ Data.Hashable.Lifted: class Eq2 t => Hashable2 t
Files
- CHANGES.md +9/−0
- examples/Main.hs +5/−3
- hashable.cabal +32/−8
- src/Data/Hashable.hs +1/−0
- src/Data/Hashable/Class.hs +103/−27
- tests/Properties.hs +2/−2
- tests/Regress.hs +2/−2
CHANGES.md view
@@ -1,5 +1,14 @@ See also https://pvp.haskell.org/faq +## Version 1.4.0.0++ * `Eq` is now a superclass of `Hashable`.+ Also `Eq1` is a superclass of `Hashable1` and `Eq2` is a superclass of `Hashable2`+ when exists.++ * Remove `Hashable1 Fixed` instance+ * Remove `Hashable1 Semi.Min/Max/...` instances as they don't have `Eq1` instance.+ ## Version 1.3.5.0 * Add `Solo` instance (base-4.15+, GHC-9+)
examples/Main.hs view
@@ -6,12 +6,12 @@ data Foo = Foo1 Int Char Bool | Foo2 String ()- deriving (Generic)+ deriving (Eq, Generic) instance Hashable Foo data Bar = Bar Double Float- deriving (Generic)+ deriving (Eq, Generic) instance Hashable Bar @@ -31,6 +31,8 @@ -- Higher Rank Hashable Examples -- ----------------------------------- +{- TODO:+ newtype WriterT w m a = WriterT { runWriterT :: m (a, w) } data Free f a = Pure a | Free (f (Free f a)) @@ -47,4 +49,4 @@ hashWithSalt = hashWithSalt1 instance (Hashable1 f, Hashable a) => Hashable (Free f a) where hashWithSalt = hashWithSalt1-+-}
hashable.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.12 name: hashable-version: 1.3.5.0+version: 1.4.0.0 synopsis: A class for types that can be converted to a hash value description: This package defines a class, 'Hashable', for types that@@ -41,8 +41,8 @@ extra-source-files: CHANGES.md- README.md include/HsHashable.h+ README.md flag integer-gmp description:@@ -61,6 +61,11 @@ manual: True default: False +flag containers+ description: 'containers >= 0.5.9.1'+ manual: False+ default: True+ library exposed-modules: Data.Hashable@@ -69,24 +74,31 @@ other-modules: Data.Hashable.Class+ Data.Hashable.Generic.Instances Data.Hashable.Imports Data.Hashable.LowLevel- Data.Hashable.Generic.Instances c-sources: cbits/fnv.c include-dirs: include hs-source-dirs: src build-depends:- base >=4.5 && <4.17- , bytestring >=0.9 && <0.12+ base >=4.5 && <4.17+ , bytestring >=0.9 && <0.12 , containers >=0.4.2.1 && <0.7- , deepseq >=1.3 && <1.5+ , deepseq >=1.3 && <1.5 , ghc-prim- , text >=0.12 && <1.3+ , text >=0.12 && <1.3 + if !impl(ghc >=9.2)+ build-depends: base-orphans >=0.8.6++ -- Integer internals if impl(ghc >=9)- build-depends: ghc-bignum ==1.0.* || ==1.2.*+ build-depends: ghc-bignum >=1.0 && <1.1 || >=1.2 && <1.3 + if !impl(ghc >=9.2)+ build-depends: ghc-bignum-orphans >=0.1 && <0.2+ else if flag(integer-gmp) build-depends: integer-gmp >=0.4 && <1.1@@ -95,6 +107,11 @@ -- this is needed for the automatic flag to be well-balanced build-depends: integer-simple + if !impl(ghc >=8)+ build-depends:+ transformers >=0.3 && <0.7+ , transformers-compat >=0.7.1 && <0.8+ if (flag(random-initial-seed) && impl(ghc)) cpp-options: -DHASHABLE_RANDOM_SEED=1 @@ -103,6 +120,13 @@ else c-sources: cbits-unix/init.c++ if flag(containers)+ build-depends: containers >=0.5.9.1++ else+ build-depends: containers <0.5.9.1+ build-depends: functor-classes-compat >=2 && <2.1 default-language: Haskell2010 other-extensions:
src/Data/Hashable.hs view
@@ -63,6 +63,7 @@ -- * Caching hashes , Hashed , hashed+ , hashedHash , unhashed , mapHashed , traverseHashed
src/Data/Hashable/Class.hs view
@@ -56,6 +56,7 @@ -- * Caching hashes , Hashed , hashed+ , hashedHash , unhashed , mapHashed , traverseHashed@@ -168,10 +169,24 @@ #endif #endif +import Data.Functor.Classes (Eq1(..),Ord1(..),Show1(..))++-- Whether we have lifted classes, in particular, Eq2+#ifndef MIN_VERSION_transformers+#define LIFTED_FUNCTOR_CLASSES 1+#else+#if !(MIN_VERSION_transformers(0,4,0) && !MIN_VERSION_transformers(0,5,0))+#define LIFTED_FUNCTOR_CLASSES 1+#endif+#endif++#ifdef LIFTED_FUNCTOR_CLASSES+import Data.Functor.Classes (Eq2)+#endif+ #if MIN_VERSION_base(4,9,0) import qualified Data.List.NonEmpty as NE import Data.Semigroup-import Data.Functor.Classes (Eq1(..),Ord1(..),Show1(..),showsUnaryWith) import Data.Functor.Compose (Compose(..)) import qualified Data.Functor.Product as FP@@ -195,6 +210,26 @@ import Data.Hashable.Imports import Data.Hashable.LowLevel +#ifdef VERSION_base_orphans+import Data.Orphans ()+#endif++#ifdef VERSION_transformers_compat+import Control.Monad.Trans.Instances ()+#endif++#ifdef VERSION_ghc_bignum_orphans+import GHC.Num.Orphans ()+#endif++#ifdef VERSION_functor_classes_compat+import Data.Map.Functor.Classes ()+import Data.Set.Functor.Classes ()+import Data.IntMap.Functor.Classes ()+import Data.Sequence.Functor.Classes ()+import Data.Tree.Functor.Classes ()+#endif+ #include "MachDeps.h" infixl 0 `hashWithSalt`@@ -213,7 +248,7 @@ -- If you are looking for 'Hashable' instance in @time@ package, -- check [time-compat](https://hackage.haskell.org/package/time-compat) ---class Hashable a where+class Eq a => Hashable a where -- | Return a hash value for the argument, using the given salt. -- -- The general contract of 'hashWithSalt' is:@@ -270,7 +305,7 @@ class GHashable arity f where ghashWithSalt :: HashArgs arity a -> Int -> f a -> Int -class Hashable1 t where+class Eq1 t => Hashable1 t where -- | Lift a hashing function through the type constructor. liftHashWithSalt :: (Int -> a -> Int) -> Int -> t a -> Int @@ -285,7 +320,11 @@ genericLiftHashWithSalt = \h salt -> ghashWithSalt (HashArgs1 h) salt . from1 {-# INLINE genericLiftHashWithSalt #-} +#if LIFTED_FUNCTOR_CLASSES+class Eq2 t => Hashable2 t where+#else class Hashable2 t where+#endif -- | Lift a hashing function through the binary type constructor. liftHashWithSalt2 :: (Int -> a -> Int) -> (Int -> b -> Int) -> Int -> t a b -> Int @@ -588,8 +627,11 @@ hash (a1, a2, a3, a4, a5) = hash a1 `hashWithSalt` a2 `hashWithSalt` a3 `hashWithSalt` a4 `hashWithSalt` a5- hashWithSalt = hashWithSalt1+ hashWithSalt s (a1, a2, a3, a4, a5) =+ s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3+ `hashWithSalt` a4 `hashWithSalt` a5 +{- instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4) => Hashable1 ((,,,,) a1 a2 a3 a4) where liftHashWithSalt = defaultLiftHashWithSalt@@ -599,15 +641,18 @@ liftHashWithSalt2 h1 h2 s (a1, a2, a3, a4, a5) = (s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3) `h1` a4 `h2` a5-+-} instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4, Hashable a5, Hashable a6) => Hashable (a1, a2, a3, a4, a5, a6) where hash (a1, a2, a3, a4, a5, a6) = hash a1 `hashWithSalt` a2 `hashWithSalt` a3 `hashWithSalt` a4 `hashWithSalt` a5 `hashWithSalt` a6- hashWithSalt = hashWithSalt1+ hashWithSalt s (a1, a2, a3, a4, a5, a6) =+ s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3+ `hashWithSalt` a4 `hashWithSalt` a5 `hashWithSalt` a6 +{- instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4, Hashable a5) => Hashable1 ((,,,,,) a1 a2 a3 a4 a5) where liftHashWithSalt = defaultLiftHashWithSalt@@ -617,7 +662,7 @@ liftHashWithSalt2 h1 h2 s (a1, a2, a3, a4, a5, a6) = (s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3 `hashWithSalt` a4) `h1` a5 `h2` a6-+-} instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4, Hashable a5, Hashable a6, Hashable a7) =>@@ -629,6 +674,7 @@ s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3 `hashWithSalt` a4 `hashWithSalt` a5 `hashWithSalt` a6 `hashWithSalt` a7 +{- instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4, Hashable a5, Hashable a6) => Hashable1 ((,,,,,,) a1 a2 a3 a4 a5 a6) where liftHashWithSalt = defaultLiftHashWithSalt @@ -637,6 +683,7 @@ liftHashWithSalt2 h1 h2 s (a1, a2, a3, a4, a5, a6, a7) = (s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3 `hashWithSalt` a4 `hashWithSalt` a5) `h1` a6 `h2` a7+-} instance Hashable (StableName a) where hash = hashStableName@@ -792,15 +839,14 @@ #if MIN_VERSION_base(4,7,0) instance Hashable (Fixed a) where hashWithSalt salt (MkFixed i) = hashWithSalt salt i--- Using hashWithSalt1 would cause needless constraint-instance Hashable1 Fixed where- liftHashWithSalt _ salt (MkFixed i) = hashWithSalt salt i #else instance Hashable (Fixed a) where hashWithSalt salt x = hashWithSalt salt (unsafeCoerce x :: Integer) #endif + #if MIN_VERSION_base(4,8,0)+-- TODO: make available on all base instance Hashable a => Hashable (Identity a) where hashWithSalt = hashWithSalt1 instance Hashable1 Identity where@@ -838,15 +884,9 @@ instance Hashable a => Hashable (Min a) where hashWithSalt p (Min a) = hashWithSalt p a --- | @since 1.3.1.0-instance Hashable1 Min where liftHashWithSalt h salt (Min a) = h salt a- instance Hashable a => Hashable (Max a) where hashWithSalt p (Max a) = hashWithSalt p a --- | @since 1.3.1.0-instance Hashable1 Max where liftHashWithSalt h salt (Max a) = h salt a- -- | __Note__: Prior to @hashable-1.3.0.0@ the hash computation included the second argument of 'Arg' which wasn't consistent with its 'Eq' instance. -- -- @since 1.3.0.0@@ -856,33 +896,49 @@ instance Hashable a => Hashable (First a) where hashWithSalt p (First a) = hashWithSalt p a --- | @since 1.3.1.0-instance Hashable1 First where liftHashWithSalt h salt (First a) = h salt a instance Hashable a => Hashable (Last a) where hashWithSalt p (Last a) = hashWithSalt p a --- | @since 1.3.1.0-instance Hashable1 Last where liftHashWithSalt h salt (Last a) = h salt a instance Hashable a => Hashable (WrappedMonoid a) where hashWithSalt p (WrapMonoid a) = hashWithSalt p a --- | @since 1.3.1.0-instance Hashable1 WrappedMonoid where liftHashWithSalt h salt (WrapMonoid a) = h salt a #if !MIN_VERSION_base(4,16,0) instance Hashable a => Hashable (Option a) where hashWithSalt p (Option a) = hashWithSalt p a +#endif++-- TODO: this instance is removed as there isn't Eq1 Min/Max, ...++#if 0 -- | @since 1.3.1.0-instance Hashable1 Option where liftHashWithSalt h salt (Option a) = liftHashWithSalt h salt a+-- instance Hashable1 Min where liftHashWithSalt h salt (Min a) = h salt a++-- | @since 1.3.1.0+-- instance Hashable1 Max where liftHashWithSalt h salt (Max a) = h salt a++-- | @since 1.3.1.0+-- instance Hashable1 First where liftHashWithSalt h salt (First a) = h salt a++-- | @since 1.3.1.0+-- instance Hashable1 Last where liftHashWithSalt h salt (Last a) = h salt a+++-- | @since 1.3.1.0+-- instance Hashable1 WrappedMonoid where liftHashWithSalt h salt (WrapMonoid a) = h salt a++-- | @since 1.3.1.0+-- instance Hashable1 Option where liftHashWithSalt h salt (Option a) = liftHashWithSalt h salt a #endif #endif -- instances for @Data.Functor.{Product,Sum,Compose}@, present -- in base-4.9 and onward. #if MIN_VERSION_base(4,9,0)+ -- | In general, @hash (Compose x) ≠ hash x@. However, @hashWithSalt@ satisfies -- its variant of this equivalence. instance (Hashable1 f, Hashable1 g, Hashable a) => Hashable (Compose f g a) where@@ -917,6 +973,12 @@ unhashed :: Hashed a -> a unhashed (Hashed a _) = a +-- | 'hash' has 'Eq' requirement.+--+-- @since 1.4.0.0+hashedHash :: Hashed a -> Int+hashedHash (Hashed _ h) = h+ -- | Uses precomputed hash to detect inequality faster instance Eq a => Eq (Hashed a) where Hashed a ha == Hashed b hb = ha == hb && a == b@@ -928,10 +990,11 @@ showsPrec d (Hashed a _) = showParen (d > 10) $ showString "hashed" . showChar ' ' . showsPrec 11 a -instance Hashable (Hashed a) where+instance Eq a => Hashable (Hashed a) where hashWithSalt = defaultHashWithSalt- hash (Hashed _ h) = h+ hash = hashedHash + -- This instance is a little unsettling. It is unusal for -- 'liftHashWithSalt' to ignore its first argument when a -- value is actually available for it to work on.@@ -955,9 +1018,17 @@ traverseHashed :: (Hashable b, Functor f) => (a -> f b) -> Hashed a -> f (Hashed b) traverseHashed f (Hashed a _) = fmap hashed (f a) +#if MIN_VERSION_base(4,9,0)+#define LIFTED_FUNCTOR_CLASSES 1+#elif defined(MIN_VERSION_transformers)+#if !(MIN_VERSION_transformers(0,4,0)) || MIN_VERSION_transformers(0,5,0)+#define LIFTED_FUNCTOR_CLASSES 1+#endif+#endif+ -- instances for @Data.Functor.Classes@ higher rank typeclasses -- in base-4.9 and onward.-#if MIN_VERSION_base(4,9,0)+#if LIFTED_FUNCTOR_CLASSES instance Eq1 Hashed where liftEq f (Hashed a ha) (Hashed b hb) = ha == hb && f a b @@ -965,7 +1036,12 @@ liftCompare f (Hashed a _) (Hashed b _) = f a b instance Show1 Hashed where- liftShowsPrec sp _ d (Hashed a _) = showsUnaryWith sp "hashed" d a+ liftShowsPrec sp _ d (Hashed a _) = showParen (d > 10) $+ showString "hashed " . sp 11 a+#else+instance Eq1 Hashed where eq1 = (==)+instance Ord1 Hashed where compare1 = compare+instance Show1 Hashed where showsPrec1 = showsPrec #endif -------------------------------------------------------------------------------
tests/Properties.hs view
@@ -154,7 +154,7 @@ -- Generics data Product2 a b = Product2 a b- deriving (Generic)+ deriving (Eq, Generic) instance (Arbitrary a, Arbitrary b) => Arbitrary (Product2 a b) where arbitrary = Product2 `liftM` arbitrary `ap` arbitrary@@ -162,7 +162,7 @@ instance (Hashable a, Hashable b) => Hashable (Product2 a b) data Product3 a b c = Product3 a b c- deriving (Generic)+ deriving (Eq, Generic) instance (Arbitrary a, Arbitrary b, Arbitrary c) => Arbitrary (Product3 a b c) where
tests/Regress.hs view
@@ -100,8 +100,8 @@ let actual = hashWithSalt salt s expected @=? actual -data SumOfNullary = S0 | S1 | S2 | S3 | S4 deriving (Generic)+data SumOfNullary = S0 | S1 | S2 | S3 | S4 deriving (Eq, Generic) instance Hashable SumOfNullary -data Nat = Z | S Nat deriving (Generic)+data Nat = Z | S Nat deriving (Eq, Generic) instance Hashable Nat