@@ -273,41 +273,83 @@ findMin (Three left k1 v1 _ _ _ _) = Just $ fromMaybe { key: k1, value: v1 } $ f
273
273
foldSubmap :: forall k v m . Ord k => Monoid m => Maybe k -> Maybe k -> (k -> v -> m ) -> Map k v -> m
274
274
foldSubmap kmin kmax f =
275
275
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.
287
317
go = case _ of
288
318
Leaf ->
289
319
mempty
290
320
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 )
294
324
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 )
300
330
in
301
331
go
302
332
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
304
334
-- | between a given lower and upper bound, treating `Nothing` as no bound i.e.
305
335
-- | 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
307
349
-- | property:
308
350
-- |
309
351
-- | ```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,
311
353
-- | let m' = submap mmin mmax m in
312
354
-- | if (maybe true (\min -> min <= key) mmin &&
313
355
-- | maybe true (\max -> max >= key) mmax)
0 commit comments