Skip to content

Commit

Permalink
Add Apply, Bind instances for HashMap (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
rhendric authored Dec 25, 2020
1 parent 19f9c23 commit 68ea3cb
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 16 deletions.
6 changes: 6 additions & 0 deletions src/Data/HashMap.purs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ instance functorWithIndexHashMap :: FunctorWithIndex k (HashMap k) where

foreign import mapWithIndexPurs :: forall k v w. (k -> v -> w) -> HashMap k v -> HashMap k w

instance applyHashMap :: Hashable k => Apply (HashMap k) where
apply = intersectionWith identity

instance bindHashMap :: Hashable k => Bind (HashMap k) where
bind m f = mapMaybeWithKey (\k -> lookup k <<< f) m

-- | The `Foldable` instance is best used with a *commutative*
-- | function/`Monoid`, since hash maps do not guarantee any
-- | particular order.
Expand Down
50 changes: 34 additions & 16 deletions test/Main.purs
Original file line number Diff line number Diff line change
Expand Up @@ -228,22 +228,27 @@ main = do
n = arbitraryHM b
in HM.union m n === HM.unionWith const m n

-- OrdMap does not have intersectionWith :/

-- log "intersectionWith agrees with OrdMap"
-- quickCheck' 10000 $ \(a :: Array (Tuple CollidingInt Int)) (b :: Array (Tuple CollidingInt Int)) c f ->
-- Array.sort (HM.toArrayBy Tuple (HM.intersectionWith f (HM.fromFoldable (a <> c)) (HM.fromFoldable (b <> map (map (_ + 1)) c)))) ===
-- Array.sort (OM.toUnfoldable (OM.intersectionWith f (OM.fromFoldable (a <> c)) (OM.fromFoldable (b <> map (map (_ + 1)) c))))

-- quickCheckWithSeed (mkSeed 143037645) 1 $ \(a :: Array (Tuple CollidingInt Int)) (b :: Array (Tuple CollidingInt Int)) c f ->
-- Array.sort (HM.toArrayBy Tuple (HM.intersectionWith f (HM.fromFoldable (a <> c)) (HM.fromFoldable (b <> map (map (_ + 1)) c)))) ===
-- Array.sort (OM.toUnfoldable (OM.intersectionWith f (OM.fromFoldable (a <> c)) (OM.fromFoldable (b <> map (map (_ + 1)) c))))

-- log "intersectionWith agrees with OrdMap 2"
-- quickCheck' 10000 $ \(a :: Array (Tuple Boolean Int)) (b :: Array (Tuple Boolean Int)) f ->
-- Array.sort (HM.toArrayBy Tuple (HM.intersectionWith f (HM.fromFoldable a) (HM.fromFoldable b))) ===
-- Array.sort (OM.toUnfoldable (OM.intersectionWith f (OM.fromFoldable a) (OM.fromFoldable b)))

log "intersectionWith agrees with OrdMap"
quickCheck' 10000 $ \(a :: Array (Tuple CollidingInt Int)) (b :: Array (Tuple CollidingInt Int)) c (f :: Int -> Int -> Int) ->
Array.sort (HM.toArrayBy Tuple (HM.intersectionWith f (HM.fromFoldable (a <> c)) (HM.fromFoldable (b <> map (map (_ + 1)) c)))) ===
Array.sort (OM.toUnfoldable (OM.intersectionWith f (OM.fromFoldable (a <> c)) (OM.fromFoldable (b <> map (map (_ + 1)) c))))

quickCheckWithSeed (mkSeed 143037645) 1 $ \(a :: Array (Tuple CollidingInt Int)) (b :: Array (Tuple CollidingInt Int)) c (f :: Int -> Int -> Int) ->
Array.sort (HM.toArrayBy Tuple (HM.intersectionWith f (HM.fromFoldable (a <> c)) (HM.fromFoldable (b <> map (map (_ + 1)) c)))) ===
Array.sort (OM.toUnfoldable (OM.intersectionWith f (OM.fromFoldable (a <> c)) (OM.fromFoldable (b <> map (map (_ + 1)) c))))

log "intersectionWith agrees with OrdMap 2"
quickCheck' 10000 $ \(a :: Array (Tuple Boolean Int)) (b :: Array (Tuple Boolean Int)) (f :: Int -> Int -> Int) ->
Array.sort (HM.toArrayBy Tuple (HM.intersectionWith f (HM.fromFoldable a) (HM.fromFoldable b))) ===
Array.sort (OM.toUnfoldable (OM.intersectionWith f (OM.fromFoldable a) (OM.fromFoldable b)))

log "map-apply is equivalent to intersectionWith"
quickCheck $ \(a :: Array (Tuple CollidingInt Int)) (b :: Array (Tuple CollidingInt Int)) (f :: Int -> Int -> Int) ->
let ma = HM.fromFoldable a
mb = HM.fromFoldable b
mx = HM.intersectionWith f ma mb
my = f <$> ma <*> mb
in mx === my

log "map difference"
quickCheck' 100000 $ \(a :: Array (Tuple CollidingInt Int)) (b :: Array (Tuple CollidingInt Int)) ->
Expand Down Expand Up @@ -419,6 +424,19 @@ main = do
quickCheck' 1000 $ \ (a :: Array Boolean) ->
Array.nub a === HM.nubHash a

log "bind"
quickCheck $ \(a :: Array (Tuple SmallInt Boolean)) (b :: Array (Tuple SmallInt Int)) (c :: Array (Tuple SmallInt Int)) k ->
let ma = HM.fromFoldable a
mb = HM.fromFoldable b
mc = HM.fromFoldable c
my = do
v <- ma
if v then mb else mc
in case HM.lookup k ma of
Just true -> HM.lookup k mb === HM.lookup k my
Just false -> HM.lookup k mc === HM.lookup k my
Nothing -> false === HM.member k my

log "Done."

t54 :: Boolean
Expand Down

0 comments on commit 68ea3cb

Please sign in to comment.