Skip to content
This repository was archived by the owner on Oct 4, 2020. It is now read-only.

Commit c326e55

Browse files
committed
Add foldSubmap and submap
Addresses #113 and #71.
1 parent 85b4a62 commit c326e55

File tree

1 file changed

+64
-22
lines changed

1 file changed

+64
-22
lines changed

src/Data/Map.purs

Lines changed: 64 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -273,41 +273,83 @@ findMin (Three left k1 v1 _ _ _ _) = Just $ fromMaybe { key: k1, value: v1 } $ f
273273
foldSubmap :: forall k v m. Ord k => Monoid m => Maybe k -> Maybe k -> (k -> v -> m) -> Map k v -> m
274274
foldSubmap kmin kmax f =
275275
let
276-
geqMin = case kmin of
277-
Just kmin' ->
278-
\x -> x >= kmin'
279-
Nothing ->
280-
const true
281-
leqMax = case kmax of
282-
Just kmax' ->
283-
\x -> x <= kmax'
284-
Nothing ->
285-
const true
286-
276+
tooSmall =
277+
case kmin of
278+
Just kmin' ->
279+
\k -> k < kmin'
280+
Nothing ->
281+
const false
282+
283+
tooLarge =
284+
case kmax of
285+
Just kmax' ->
286+
\k -> k > kmax'
287+
Nothing ->
288+
const false
289+
290+
inBounds =
291+
case kmin, kmax of
292+
Just kmin', Just kmax' ->
293+
\k -> kmin' <= k && k <= kmax'
294+
Just kmin', Nothing ->
295+
\k -> kmin' <= k
296+
Nothing, Just kmax' ->
297+
\k -> k <= kmax'
298+
Nothing, Nothing ->
299+
const true
300+
301+
-- We can take advantage of the invariants of the tree structure to reduce
302+
-- the amount of work we need to do. For example, in the following tree:
303+
--
304+
-- [2][4]
305+
-- / | \
306+
-- / | \
307+
-- [1] [3] [5]
308+
--
309+
-- If we are given a lower bound of 3, we do not need to inspect the left
310+
-- subtree, because we know that every entry in it is less than or equal to
311+
-- 2. Similarly, if we are given a lower bound of 5, we do not need to
312+
-- inspect the central subtree, because we know that every entry in it must
313+
-- be less than or equal to 4.
314+
--
315+
-- Unfortunately we cannot extract `if cond then x else mempty` into a
316+
-- function because of strictness.
287317
go = case _ of
288318
Leaf ->
289319
mempty
290320
Two left k v right ->
291-
(if geqMin k then go left else mempty)
292-
<> (if geqMin k && leqMax k then f k v else mempty)
293-
<> (if leqMax k then go right else mempty)
321+
(if tooSmall k then mempty else go left)
322+
<> (if inBounds k then f k v else mempty)
323+
<> (if tooLarge k then mempty else go right)
294324
Three left k1 v1 mid k2 v2 right ->
295-
(if geqMin k1 then go left else mempty)
296-
<> (if geqMin k1 && leqMax k1 then f k1 v1 else mempty)
297-
<> (if geqMin k1 && leqMax k2 then go mid else mempty)
298-
<> (if geqMin k2 && leqMax k2 then f k2 v2 else mempty)
299-
<> (if leqMax k2 then go right else mempty)
325+
(if tooSmall k1 then mempty else go left)
326+
<> (if inBounds k1 then f k1 v1 else mempty)
327+
<> (if tooSmall k2 || tooLarge k1 then mempty else go mid)
328+
<> (if inBounds k2 then f k2 v2 else mempty)
329+
<> (if tooLarge k2 then mempty else go right)
300330
in
301331
go
302332

303-
-- | Returns a new map containing all entries of the argument map which lie
333+
-- | Returns a new map containing all entries of the given map which lie
304334
-- | between a given lower and upper bound, treating `Nothing` as no bound i.e.
305335
-- | including the smallest (or largest) key in the map, no matter how small
306-
-- | (or large) it is. The function is entirely specified by the following
336+
-- | (or large) it is. For example:
337+
-- |
338+
-- | ```purescript
339+
-- | submap (Just 1) (Just 2)
340+
-- | (fromFoldable [Tuple 0 "zero", Tuple 1 "one", Tuple 2 "two", Tuple 3 "three"])
341+
-- | == fromFoldable [Tuple 1 "one", Tuple 2 "two"]
342+
-- |
343+
-- | submap Nothing (Just 2)
344+
-- | (fromFoldable [Tuple 0 "zero", Tuple 1 "one", Tuple 2 "two", Tuple 3 "three"])
345+
-- | == fromFoldable [Tuple 0 "zero", Tuple 1 "one", Tuple 2 "two"]
346+
-- | ```
347+
-- |
348+
-- | The function is entirely specified by the following
307349
-- | property:
308350
-- |
309351
-- | ```purescript
310-
-- | forall m :: Map k v, mmin :: Maybe k, mmax :: Maybe k, key :: k,
352+
-- | Given any m :: Map k v, mmin :: Maybe k, mmax :: Maybe k, key :: k,
311353
-- | let m' = submap mmin mmax m in
312354
-- | if (maybe true (\min -> min <= key) mmin &&
313355
-- | maybe true (\max -> max >= key) mmax)

0 commit comments

Comments
 (0)