Skip to content

Commit d63c873

Browse files
Add Apply instance for Map (#16)
Co-authored-by: Thomas Honeyman <[email protected]>
1 parent 7232230 commit d63c873

File tree

3 files changed

+30
-6
lines changed

3 files changed

+30
-6
lines changed

src/Data/Map/Internal.purs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ instance functorWithIndexMap :: FunctorWithIndex k (Map k) where
106106
mapWithIndex f (Two left k v right) = Two (mapWithIndex f left) k (f k v) (mapWithIndex f right)
107107
mapWithIndex f (Three left k1 v1 mid k2 v2 right) = Three (mapWithIndex f left) k1 (f k1 v1) (mapWithIndex f mid) k2 (f k2 v2) (mapWithIndex f right)
108108

109+
instance applyMap :: Ord k => Apply (Map k) where
110+
apply = intersectionWith identity
111+
112+
instance bindMap :: Ord k => Bind (Map k) where
113+
bind m f = mapMaybeWithKey (\k -> lookup k <<< f) m
114+
109115
instance foldableMap :: Foldable (Map k) where
110116
foldl f z m = foldl f z (values m)
111117
foldr f z m = foldr f z (values m)

src/Data/Set.purs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ properSubset s1 s2 = subset s1 s2 && (s1 /= s2)
162162

163163
-- | The set of elements which are in both the first and second set
164164
intersection :: forall a. Ord a => Set a -> Set a -> Set a
165-
intersection s1 s2 = fromFoldable (ST.run (STArray.empty >>= intersect >>= STArray.unsafeFreeze))
165+
intersection s1 s2 = fromFoldable (ST.run (STArray.new >>= intersect >>= STArray.unsafeFreeze))
166166
where
167167
toArray = Array.fromFoldable <<< toList
168168
ls = toArray s1

test/Test/Data/Map.purs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Prelude
44

55
import Control.Alt ((<|>))
66
import Data.Array as A
7+
import Data.Array.NonEmpty as NEA
78
import Data.Foldable (foldl, for_, all, and)
89
import Data.FoldableWithIndex (foldrWithIndex)
910
import Data.Function (on)
@@ -44,7 +45,7 @@ instance showSmallKey :: Show SmallKey where
4445
show J = "J"
4546

4647
instance arbSmallKey :: Arbitrary SmallKey where
47-
arbitrary = elements $ A :| [B, C, D, E, F, G, H, I, J]
48+
arbitrary = elements $ NEA.fromNonEmpty $ A :| [B, C, D, E, F, G, H, I, J]
4849

4950
data Instruction k v = Insert k v | Delete k
5051

@@ -53,7 +54,7 @@ instance showInstruction :: (Show k, Show v) => Show (Instruction k v) where
5354
show (Delete k) = "Delete (" <> show k <> ")"
5455

5556
instance arbInstruction :: (Arbitrary k, Arbitrary v) => Arbitrary (Instruction k v) where
56-
arbitrary = oneOf $ (Insert <$> arbitrary <*> arbitrary) :| [Delete <$> arbitrary]
57+
arbitrary = oneOf $ NEA.fromNonEmpty $ (Insert <$> arbitrary <*> arbitrary) :| [Delete <$> arbitrary]
5758

5859
runInstructions :: forall k v. Ord k => List (Instruction k v) -> M.Map k v -> M.Map k v
5960
runInstructions instrs t0 = foldl step t0 instrs
@@ -240,6 +241,12 @@ mapTests = do
240241
Nothing -> not (M.member k m1 && M.member k m2)
241242
Just v -> Just v == (op <$> M.lookup k m1 <*> M.lookup k m2)
242243

244+
log "map-apply is equivalent to intersectionWith"
245+
for_ [(+), (*)] $ \op ->
246+
quickCheck $ \(TestMap m1) (TestMap m2) ->
247+
let u = M.intersectionWith op m1 m2 :: M.Map SmallKey Int
248+
in u == (op <$> m1 <*> m2)
249+
243250
log "difference"
244251
quickCheck $ \(TestMap m1) (TestMap m2) ->
245252
let d = M.difference (m1 :: M.Map SmallKey Int) (m2 :: M.Map SmallKey String)
@@ -315,23 +322,23 @@ mapTests = do
315322

316323
log "filterWithKey keeps those keys for which predicate is true"
317324
quickCheck $ \(TestMap s :: TestMap String Int) p ->
318-
A.all (uncurry p) (M.toUnfoldable (M.filterWithKey p s) :: Array (Tuple String Int))
325+
all (uncurry p) (M.toUnfoldable (M.filterWithKey p s) :: Array (Tuple String Int))
319326

320327
log "filterKeys gives submap"
321328
quickCheck $ \(TestMap s :: TestMap String Int) p ->
322329
M.isSubmap (M.filterKeys p s) s
323330

324331
log "filterKeys keeps those keys for which predicate is true"
325332
quickCheck $ \(TestMap s :: TestMap String Int) p ->
326-
A.all p (M.keys (M.filterKeys p s))
333+
all p (M.keys (M.filterKeys p s))
327334

328335
log "filter gives submap"
329336
quickCheck $ \(TestMap s :: TestMap String Int) p ->
330337
M.isSubmap (M.filter p s) s
331338

332339
log "filter keeps those values for which predicate is true"
333340
quickCheck $ \(TestMap s :: TestMap String Int) p ->
334-
A.all p (M.values (M.filter p s))
341+
all p (M.values (M.filter p s))
335342

336343
log "submap with no bounds = id"
337344
quickCheck \(TestMap m :: TestMap SmallKey Int) ->
@@ -371,6 +378,17 @@ mapTests = do
371378
let outList = foldrWithIndex (\i a b -> (Tuple i a) : b) Nil m
372379
in outList == sort outList
373380

381+
log "bind"
382+
quickCheck $ \(TestMap m1) (TestMap m2 :: TestMap SmallKey Int) (TestMap m3) k ->
383+
let
384+
u = do
385+
v <- m1
386+
if v then m2 else m3
387+
in case M.lookup k m1 of
388+
Just true -> M.lookup k m2 == M.lookup k u
389+
Just false -> M.lookup k m3 == M.lookup k u
390+
Nothing -> not $ M.member k u
391+
374392
log "catMaybes creates a new map of size less than or equal to the original"
375393
quickCheck \(TestMap m :: TestMap Int (Maybe Int)) -> do
376394
let result = M.catMaybes m

0 commit comments

Comments
 (0)