Skip to content

Commit de1ae9e

Browse files
committed
Add instance for Data.Functor.Classes
1 parent 42b79ff commit de1ae9e

File tree

4 files changed

+101
-11
lines changed

4 files changed

+101
-11
lines changed

CHANGES.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 0.2.8.0
2+
3+
* Add `Eq1/2`, `Show1/2`, `Read1` instances with `base-4.9`
4+
5+
* `Eq (HashSet a)` doesn't require `Hashable a` anymore, only `Eq a`.
6+
17
## 0.2.7.2
28

39
* Don't use -fregs-graphs

Data/HashMap/Base.hs

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ module Data.HashMap.Base
8989
, updateOrConcatWith
9090
, updateOrConcatWithKey
9191
, filterMapAux
92+
, equalKeys
9293
) where
9394

9495
#if __GLASGOW_HASKELL__ < 710
@@ -125,6 +126,9 @@ import GHC.Exts (isTrue#)
125126
import qualified GHC.Exts as Exts
126127
#endif
127128

129+
#if MIN_VERSION_base(4,9,0)
130+
import Data.Functor.Classes
131+
#endif
128132

129133
------------------------------------------------------------------------
130134

@@ -203,6 +207,25 @@ type Hash = Word
203207
type Bitmap = Word
204208
type Shift = Int
205209

210+
#if MIN_VERSION_base(4,9,0)
211+
instance Show2 HashMap where
212+
liftShowsPrec2 spk slk spv slv d m =
213+
showsUnaryWith (liftShowsPrec sp sl) "fromList" d (toList m)
214+
where
215+
sp = liftShowsPrec2 spk slk spv slv
216+
sl = liftShowList2 spk slk spv slv
217+
218+
instance Show k => Show1 (HashMap k) where
219+
liftShowsPrec = liftShowsPrec2 showsPrec showList
220+
221+
instance (Eq k, Hashable k, Read k) => Read1 (HashMap k) where
222+
liftReadsPrec rp rl = readsData $
223+
readsUnaryWith (liftReadsPrec rp' rl') "fromList" fromList
224+
where
225+
rp' = liftReadsPrec rp rl
226+
rl' = liftReadList rp rl
227+
#endif
228+
206229
instance (Eq k, Hashable k, Read k, Read e) => Read (HashMap k e) where
207230
readPrec = parens $ prec 10 $ do
208231
Ident "fromList" <- lexP
@@ -218,26 +241,74 @@ instance (Show k, Show v) => Show (HashMap k v) where
218241
instance Traversable (HashMap k) where
219242
traverse f = traverseWithKey (const f)
220243

244+
#if MIN_VERSION_base(4,9,0)
245+
instance Eq2 HashMap where
246+
liftEq2 = equal
247+
248+
instance Eq k => Eq1 (HashMap k) where
249+
liftEq = equal (==)
250+
#endif
251+
221252
instance (Eq k, Eq v) => Eq (HashMap k v) where
222-
(==) = equal
253+
(==) = equal (==) (==)
223254

224-
equal :: (Eq k, Eq v) => HashMap k v -> HashMap k v -> Bool
225-
equal t1 t2 = go (toList' t1 []) (toList' t2 [])
255+
equal :: (k -> k' -> Bool) -> (v -> v' -> Bool)
256+
-> HashMap k v -> HashMap k' v' -> Bool
257+
equal eqk eqv t1 t2 = go (toList' t1 []) (toList' t2 [])
226258
where
227259
-- If the two trees are the same, then their lists of 'Leaf's and
228260
-- 'Collision's read from left to right should be the same (modulo the
229261
-- order of elements in 'Collision').
230262

231263
go (Leaf k1 l1 : tl1) (Leaf k2 l2 : tl2)
232-
| k1 == k2 && l1 == l2
264+
| k1 == k2 && leafEq l1 l2
233265
= go tl1 tl2
234266
go (Collision k1 ary1 : tl1) (Collision k2 ary2 : tl2)
235267
| k1 == k2 && A.length ary1 == A.length ary2 &&
236-
L.null (A.toList ary1 L.\\ A.toList ary2)
268+
isPermutationBy leafEq (A.toList ary1) (A.toList ary2)
237269
= go tl1 tl2
238270
go [] [] = True
239271
go _ _ = False
240272

273+
leafEq (L k v) (L k' v') = eqk k k' && eqv v v'
274+
275+
-- Note: previous implemenation isPermutation = null (as // bs)
276+
-- was O(n^2) too.
277+
--
278+
-- This assumes lists are of equal length
279+
isPermutationBy :: (a -> b -> Bool) -> [a] -> [b] -> Bool
280+
isPermutationBy f = go
281+
where
282+
f' = flip f
283+
284+
go [] [] = True
285+
go (x : xs) (y : ys)
286+
| f x y = go xs ys
287+
| otherwise = go (deleteBy f' y xs) (deleteBy f x ys)
288+
go [] (_ : _) = False
289+
go (_ : _) [] = False
290+
291+
-- Data.List.deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]
292+
deleteBy :: (a -> b -> Bool) -> a -> [b] -> [b]
293+
deleteBy _ _ [] = []
294+
deleteBy eq x (y:ys) = if x `eq` y then ys else y : deleteBy eq x ys
295+
296+
-- Same as 'equal' but doesn't compare the values.
297+
equalKeys :: (k -> k' -> Bool) -> HashMap k v -> HashMap k' v' -> Bool
298+
equalKeys eq t1 t2 = go (toList' t1 []) (toList' t2 [])
299+
where
300+
go (Leaf k1 l1 : tl1) (Leaf k2 l2 : tl2)
301+
| k1 == k2 && leafEq l1 l2
302+
= go tl1 tl2
303+
go (Collision k1 ary1 : tl1) (Collision k2 ary2 : tl2)
304+
| k1 == k2 && A.length ary1 == A.length ary2 &&
305+
isPermutationBy leafEq (A.toList ary1) (A.toList ary2)
306+
= go tl1 tl2
307+
go [] [] = True
308+
go _ _ = False
309+
310+
leafEq (L k _) (L k' _) = eq k k'
311+
241312
instance (Hashable k, Hashable v) => Hashable (HashMap k v) where
242313
hashWithSalt salt hm = go salt (toList' hm [])
243314
where

Data/HashSet.hs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ module Data.HashSet
7474

7575
import Control.DeepSeq (NFData(..))
7676
import Data.Data hiding (Typeable)
77-
import Data.HashMap.Base (HashMap, foldrWithKey)
77+
import Data.HashMap.Base (HashMap, foldrWithKey, equalKeys)
7878
import Data.Hashable (Hashable(hashWithSalt))
7979
#if __GLASGOW_HASKELL__ >= 711
8080
import Data.Semigroup (Semigroup(..), Monoid(..))
@@ -93,6 +93,10 @@ import Text.Read
9393
import qualified GHC.Exts as Exts
9494
#endif
9595

96+
#if MIN_VERSION_base(4,9,0)
97+
import Data.Functor.Classes
98+
#endif
99+
96100
-- | A set of values. A set cannot contain duplicate values.
97101
newtype HashSet a = HashSet {
98102
asMap :: HashMap a ()
@@ -106,12 +110,15 @@ instance (NFData a) => NFData (HashSet a) where
106110
rnf = rnf . asMap
107111
{-# INLINE rnf #-}
108112

109-
instance (Hashable a, Eq a) => Eq (HashSet a) where
110-
-- This performs two passes over the tree.
111-
a == b = foldr f True b && size a == size b
112-
where f i = (&& i `member` a)
113+
instance (Eq a) => Eq (HashSet a) where
114+
HashSet a == HashSet b = equalKeys (==) a b
113115
{-# INLINE (==) #-}
114116

117+
#if MIN_VERSION_base(4,9,0)
118+
instance Eq1 HashSet where
119+
liftEq eq (HashSet a) (HashSet b) = equalKeys eq a b
120+
#endif
121+
115122
instance Foldable.Foldable HashSet where
116123
foldr = Data.HashSet.foldr
117124
{-# INLINE foldr #-}
@@ -140,6 +147,12 @@ instance (Eq a, Hashable a, Read a) => Read (HashSet a) where
140147

141148
readListPrec = readListPrecDefault
142149

150+
#if MIN_VERSION_base(4,9,0)
151+
instance Show1 HashSet where
152+
liftShowsPrec sp sl d m =
153+
showsUnaryWith (liftShowsPrec sp sl) "fromList" d (toList m)
154+
#endif
155+
143156
instance (Show a) => Show (HashSet a) where
144157
showsPrec d m = showParen (d > 10) $
145158
showString "fromList " . shows (toList m)

unordered-containers.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: unordered-containers
2-
version: 0.2.7.2
2+
version: 0.2.8.0
33
synopsis: Efficient hashing-based container types
44
description:
55
Efficient hashing-based container types. The containers have been

0 commit comments

Comments
 (0)