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

Commit 85b4a62

Browse files
committed
foldSubmap (wip)
1 parent 9365860 commit 85b4a62

File tree

3 files changed

+100
-3
lines changed

3 files changed

+100
-3
lines changed

bower.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
},
3030
"devDependencies": {
3131
"purescript-quickcheck": "^4.0.0",
32-
"purescript-minibench": "^1.0.0"
32+
"purescript-minibench": "^1.0.0",
33+
"purescript-psci-support": "^3.0.0"
3334
}
3435
}

src/Data/Map.purs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ module Data.Map
1616
, lookupGT
1717
, findMin
1818
, findMax
19+
, foldSubmap
20+
, submap
1921
, fromFoldable
2022
, fromFoldableWith
2123
, toUnfoldable
@@ -44,7 +46,7 @@ import Data.Foldable (foldl, foldMap, foldr, class Foldable)
4446
import Data.List (List(..), (:), length, nub)
4547
import Data.List.Lazy as LL
4648
import Data.Maybe (Maybe(..), maybe, isJust, fromMaybe)
47-
import Data.Monoid (class Monoid)
49+
import Data.Monoid (class Monoid, mempty)
4850
import Data.Ord (class Ord1)
4951
import Data.Traversable (traverse, class Traversable)
5052
import Data.Tuple (Tuple(Tuple), snd, uncurry)
@@ -254,6 +256,67 @@ findMin Leaf = Nothing
254256
findMin (Two left k1 v1 _) = Just $ fromMaybe { key: k1, value: v1 } $ findMin left
255257
findMin (Three left k1 v1 _ _ _ _) = Just $ fromMaybe { key: k1, value: v1 } $ findMin left
256258

259+
-- | Fold over the entries of a given map where the key is between a lower and
260+
-- | an upper bound. Passing `Nothing` as either the lower or upper bound
261+
-- | argument means that the fold has no lower or upper bound, i.e. the fold
262+
-- | starts from (or ends with) the smallest (or largest) key in the map.
263+
-- |
264+
-- | ```purescript
265+
-- | foldSubmap (Just 1) (Just 2) (\_ v -> [v])
266+
-- | (fromFoldable [Tuple 0 "zero", Tuple 1 "one", Tuple 2 "two", Tuple 3 "three"])
267+
-- | == ["one", "two"]
268+
-- |
269+
-- | foldSubmap Nothing (Just 2) (\_ v -> [v])
270+
-- | (fromFoldable [Tuple 0 "zero", Tuple 1 "one", Tuple 2 "two", Tuple 3 "three"])
271+
-- | == ["zero", "one", "two"]
272+
-- | ```
273+
foldSubmap :: forall k v m. Ord k => Monoid m => Maybe k -> Maybe k -> (k -> v -> m) -> Map k v -> m
274+
foldSubmap kmin kmax f =
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+
287+
go = case _ of
288+
Leaf ->
289+
mempty
290+
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)
294+
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)
300+
in
301+
go
302+
303+
-- | Returns a new map containing all entries of the argument map which lie
304+
-- | between a given lower and upper bound, treating `Nothing` as no bound i.e.
305+
-- | 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
307+
-- | property:
308+
-- |
309+
-- | ```purescript
310+
-- | forall m :: Map k v, mmin :: Maybe k, mmax :: Maybe k, key :: k,
311+
-- | let m' = submap mmin mmax m in
312+
-- | if (maybe true (\min -> min <= key) mmin &&
313+
-- | maybe true (\max -> max >= key) mmax)
314+
-- | then lookup key m == lookup key m'
315+
-- | else not (member key m')
316+
-- | ```
317+
submap :: forall k v. Ord k => Maybe k -> Maybe k -> Map k v -> Map k v
318+
submap kmin kmax = foldSubmap kmin kmax singleton
319+
257320
-- | Test if a key is a member of a map
258321
member :: forall k v. Ord k => k -> Map k v -> Boolean
259322
member k m = isJust (k `lookup` m)

test/Test/Data/Map.purs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Data.List (List(Cons), groupBy, length, nubBy, singleton, sort, sortBy)
1313
import Data.List.NonEmpty as NEL
1414
import Data.Map as M
1515
import Data.Map.Gen (genMap)
16-
import Data.Maybe (Maybe(..), fromMaybe)
16+
import Data.Maybe (Maybe(..), fromMaybe, maybe)
1717
import Data.NonEmpty ((:|))
1818
import Data.Tuple (Tuple(..), fst, uncurry)
1919
import Partial.Unsafe (unsafePartial)
@@ -300,3 +300,36 @@ mapTests = do
300300
log "filter keeps those values for which predicate is true"
301301
quickCheck $ \(TestMap s :: TestMap String Int) p ->
302302
A.all p (M.values (M.filter p s))
303+
304+
log "submap with no bounds = id"
305+
quickCheck \(TestMap m :: TestMap SmallKey Int) ->
306+
M.submap Nothing Nothing m === m
307+
308+
log "submap with lower bound"
309+
quickCheck' 1 $
310+
M.submap (Just B) Nothing (M.fromFoldable [Tuple A 0, Tuple B 0])
311+
== M.fromFoldable [Tuple B 0]
312+
313+
log "submap with upper bound"
314+
quickCheck' 1 $
315+
M.submap Nothing (Just A) (M.fromFoldable [Tuple A 0, Tuple B 0])
316+
== M.fromFoldable [Tuple A 0]
317+
318+
log "submap with lower & upper bound"
319+
quickCheck' 1 $
320+
M.submap (Just B) (Just B) (M.fromFoldable [Tuple A 0, Tuple B 0, Tuple C 0])
321+
== M.fromFoldable [Tuple B 0]
322+
323+
log "submap"
324+
quickCheck' 1000 \(TestMap m :: TestMap SmallKey Int) mmin mmax key ->
325+
let
326+
m' = M.submap mmin mmax m
327+
in
328+
(if (maybe true (\min -> min <= key) mmin &&
329+
maybe true (\max -> max >= key) mmax)
330+
then M.lookup key m == M.lookup key m'
331+
else (not (M.member key m')))
332+
<?> "m: " <> show m
333+
<> ", mmin: " <> show mmin
334+
<> ", mmax: " <> show mmax
335+
<> ", key: " <> show key

0 commit comments

Comments
 (0)