@@ -46,6 +46,10 @@ module Data.Hashable.Class
46
46
, hashWithSalt1
47
47
, hashWithSalt2
48
48
, defaultLiftHashWithSalt
49
+ -- * Caching hashes
50
+ , Hashed
51
+ , hashed
52
+ , unhashed
49
53
) where
50
54
51
55
import Control.Applicative (Const (.. ))
@@ -148,12 +152,15 @@ import GHC.Exts (Word(..))
148
152
#if MIN_VERSION_base(4,9,0)
149
153
import qualified Data.List.NonEmpty as NE
150
154
import Data.Semigroup
155
+ import Data.Functor.Classes (Eq1 (.. ),Ord1 (.. ),Show1 (.. ),showsUnaryWith )
151
156
152
157
import Data.Functor.Compose (Compose (.. ))
153
158
import qualified Data.Functor.Product as FP
154
159
import qualified Data.Functor.Sum as FS
155
160
#endif
156
161
162
+ import Data.String (IsString (.. ))
163
+
157
164
#include "MachDeps.h"
158
165
159
166
infixl 0 `hashWithSalt`
@@ -799,4 +806,56 @@ instance (Hashable1 f, Hashable1 g, Hashable a) => Hashable (FS.Sum f g a) where
799
806
hashWithSalt = hashWithSalt1
800
807
#endif
801
808
809
+ -- | A hashable value along with the result of the 'hash' function.
810
+ data Hashed a = Hashed a {- # UNPACK #-} !Int
811
+ deriving (Typeable )
812
+
813
+ -- | Wrap a hashable value, caching the 'hash' function result.
814
+ hashed :: Hashable a => a -> Hashed a
815
+ hashed a = Hashed a (hash a)
816
+
817
+ -- | Unwrap hashed value.
818
+ unhashed :: Hashed a -> a
819
+ unhashed (Hashed a _) = a
820
+
821
+ -- | Uses precomputed hash to detect inequality faster
822
+ instance Eq a => Eq (Hashed a ) where
823
+ Hashed a ha == Hashed b hb = ha == hb && a == b
824
+
825
+ instance Ord a => Ord (Hashed a ) where
826
+ Hashed a _ `compare` Hashed b _ = a `compare` b
827
+
828
+ instance Show a => Show (Hashed a ) where
829
+ showsPrec d (Hashed a _) = showParen (d > 10 ) $
830
+ showString " hashed" . showChar ' ' . showsPrec 11 a
831
+
832
+ instance Hashable (Hashed a ) where
833
+ hashWithSalt = defaultHashWithSalt
834
+ hash (Hashed _ h) = h
835
+
836
+ -- This instance is a little unsettling. It is unusal for
837
+ -- 'liftHashWithSalt' to ignore its first argument when a
838
+ -- value is actually available for it to work on.
839
+ instance Hashable1 Hashed where
840
+ liftHashWithSalt _ s (Hashed _ h) = defaultHashWithSalt s h
841
+
842
+ instance (IsString a , Hashable a ) => IsString (Hashed a ) where
843
+ fromString s = let r = fromString s in Hashed r (hash r)
844
+
845
+ instance Foldable Hashed where
846
+ foldr f acc (Hashed a _) = f a acc
847
+
848
+ -- instances for @Data.Functor.Classes@ higher rank typeclasses
849
+ -- in base-4.9 and onward.
850
+ #if MIN_VERSION_base(4,9,0)
851
+ instance Eq1 Hashed where
852
+ liftEq f (Hashed a ha) (Hashed b hb) = ha == hb && f a b
853
+
854
+ instance Ord1 Hashed where
855
+ liftCompare f (Hashed a _) (Hashed b _) = f a b
856
+
857
+ instance Show1 Hashed where
858
+ liftShowsPrec sp _ d (Hashed a _) = showsUnaryWith sp " hashed" d a
859
+ #endif
860
+
802
861
0 commit comments