Skip to content

Commit 71e293e

Browse files
authored
Merge pull request #337 from treeowl/map-min-max
Quit using deleteFindMin and deleteFindMax
2 parents 4f70ddd + 3f6786b commit 71e293e

File tree

9 files changed

+197
-61
lines changed

9 files changed

+197
-61
lines changed

Data/Map/Internal.hs

Lines changed: 95 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{-# LANGUAGE CPP #-}
22
{-# LANGUAGE BangPatterns #-}
3+
{-# LANGUAGE PatternGuards #-}
34
#if __GLASGOW_HASKELL__
45
{-# LANGUAGE DeriveDataTypeable, StandaloneDeriving #-}
56
#endif
@@ -131,7 +132,7 @@ module Data.Map.Internal (
131132
Map(..) -- instance Eq,Show,Read
132133

133134
-- * Operators
134-
, (!), (\\)
135+
, (!), (!?), (\\)
135136

136137
-- * Query
137138
, null
@@ -312,6 +313,8 @@ module Data.Map.Internal (
312313
, splitAt
313314

314315
-- * Min\/Max
316+
, lookupMin
317+
, lookupMax
315318
, findMin
316319
, findMax
317320
, deleteMin
@@ -406,7 +409,7 @@ import Data.Coerce
406409
{--------------------------------------------------------------------
407410
Operators
408411
--------------------------------------------------------------------}
409-
infixl 9 !,\\ --
412+
infixl 9 !,!?,\\ --
410413

411414
-- | /O(log n)/. Find the value at a key.
412415
-- Calls 'error' when the element can not be found.
@@ -417,14 +420,26 @@ infixl 9 !,\\ --
417420
(!) :: Ord k => Map k a -> k -> a
418421
(!) m k = find k m
419422
#if __GLASGOW_HASKELL__
420-
{-# INLINABLE (!) #-}
423+
{-# INLINE (!) #-}
424+
#endif
425+
426+
-- | /O(log n)/. Find the value at a key.
427+
-- Returns 'Nothing' when the element can not be found.
428+
--
429+
-- prop> fromList [(5, 'a'), (3, 'b')] !? 1 == Nothing
430+
-- prop> fromList [(5, 'a'), (3, 'b')] !? 5 == Just 'a'
431+
432+
(!?) :: Ord k => Map k a -> k -> Maybe a
433+
(!?) m k = lookup k m
434+
#if __GLASGOW_HASKELL__
435+
{-# INLINE (!?) #-}
421436
#endif
422437

423438
-- | Same as 'difference'.
424439
(\\) :: Ord k => Map k a -> Map k b -> Map k a
425440
m1 \\ m2 = difference m1 m2
426441
#if __GLASGOW_HASKELL__
427-
{-# INLINABLE (\\) #-}
442+
{-# INLINE (\\) #-}
428443
#endif
429444

430445
{--------------------------------------------------------------------
@@ -1554,25 +1569,56 @@ deleteAt !i t =
15541569
{--------------------------------------------------------------------
15551570
Minimal, Maximal
15561571
--------------------------------------------------------------------}
1572+
1573+
lookupMinSure :: k -> a -> Map k a -> (k, a)
1574+
lookupMinSure k a Tip = (k, a)
1575+
lookupMinSure _ _ (Bin _ k a l _) = lookupMinSure k a l
1576+
1577+
-- | /O(log n)/. The minimal key of the map. Returns 'Nothing' if the map is empty.
1578+
--
1579+
-- > lookupMin (fromList [(5,"a"), (3,"b")]) == Just (3,"b")
1580+
-- > findMin empty = Nothing
1581+
--
1582+
-- @since 0.5.9
1583+
1584+
lookupMin :: Map k a -> Maybe (k,a)
1585+
lookupMin Tip = Nothing
1586+
lookupMin (Bin _ k x l _) = Just $! lookupMinSure k x l
1587+
15571588
-- | /O(log n)/. The minimal key of the map. Calls 'error' if the map is empty.
15581589
--
15591590
-- > findMin (fromList [(5,"a"), (3,"b")]) == (3,"b")
15601591
-- > findMin empty Error: empty map has no minimal element
15611592

15621593
findMin :: Map k a -> (k,a)
1563-
findMin (Bin _ kx x Tip _) = (kx,x)
1564-
findMin (Bin _ _ _ l _) = findMin l
1565-
findMin Tip = error "Map.findMin: empty map has no minimal element"
1594+
findMin t
1595+
| Just r <- lookupMin t = r
1596+
| otherwise = error "Map.findMin: empty map has no minimal element"
15661597

15671598
-- | /O(log n)/. The maximal key of the map. Calls 'error' if the map is empty.
15681599
--
15691600
-- > findMax (fromList [(5,"a"), (3,"b")]) == (5,"a")
15701601
-- > findMax empty Error: empty map has no maximal element
15711602

1603+
lookupMaxSure :: k -> a -> Map k a -> (k, a)
1604+
lookupMaxSure k a Tip = (k, a)
1605+
lookupMaxSure _ _ (Bin _ k a _ r) = lookupMaxSure k a r
1606+
1607+
-- | /O(log n)/. The maximal key of the map. Returns 'Nothing' if the map is empty.
1608+
--
1609+
-- > lookupMax (fromList [(5,"a"), (3,"b")]) == Just (5,"a")
1610+
-- > lookupMax empty = Nothing
1611+
--
1612+
-- @since 0.5.9
1613+
1614+
lookupMax :: Map k a -> Maybe (k, a)
1615+
lookupMax Tip = Nothing
1616+
lookupMax (Bin _ k x _ r) = Just $! lookupMaxSure k x r
1617+
15721618
findMax :: Map k a -> (k,a)
1573-
findMax (Bin _ kx x _ Tip) = (kx,x)
1574-
findMax (Bin _ _ _ _ r) = findMax r
1575-
findMax Tip = error "Map.findMax: empty map has no maximal element"
1619+
findMax t
1620+
| Just r <- lookupMax t = r
1621+
| otherwise = error "Map.findMax: empty map has no maximal element"
15761622

15771623
-- | /O(log n)/. Delete the minimal key. Returns an empty map if the map is empty.
15781624
--
@@ -1645,7 +1691,9 @@ updateMaxWithKey f (Bin _ kx x l r) = balanceL kx x l (updateMaxWithKey f r)
16451691

16461692
minViewWithKey :: Map k a -> Maybe ((k,a), Map k a)
16471693
minViewWithKey Tip = Nothing
1648-
minViewWithKey x = Just $! deleteFindMin x
1694+
minViewWithKey (Bin _ k x l r) =
1695+
case minViewSure k x l r of
1696+
MinView km xm t -> Just ((km, xm), t)
16491697

16501698
-- | /O(log n)/. Retrieves the maximal (key,value) pair of the map, and
16511699
-- the map stripped of that element, or 'Nothing' if passed an empty map.
@@ -1655,7 +1703,9 @@ minViewWithKey x = Just $! deleteFindMin x
16551703

16561704
maxViewWithKey :: Map k a -> Maybe ((k,a), Map k a)
16571705
maxViewWithKey Tip = Nothing
1658-
maxViewWithKey x = Just $! deleteFindMax x
1706+
maxViewWithKey (Bin _ k x l r) =
1707+
case maxViewSure k x l r of
1708+
MaxView km xm t -> Just ((km, xm), t)
16591709

16601710
-- | /O(log n)/. Retrieves the value associated with minimal key of the
16611711
-- map, and the map stripped of that element, or 'Nothing' if passed an
@@ -1665,8 +1715,9 @@ maxViewWithKey x = Just $! deleteFindMax x
16651715
-- > minView empty == Nothing
16661716

16671717
minView :: Map k a -> Maybe (a, Map k a)
1668-
minView Tip = Nothing
1669-
minView x = Just $! (first snd $ deleteFindMin x)
1718+
minView t = case minViewWithKey t of
1719+
Nothing -> Nothing
1720+
Just ((_, x), t') -> Just (x, t')
16701721

16711722
-- | /O(log n)/. Retrieves the value associated with maximal key of the
16721723
-- map, and the map stripped of that element, or 'Nothing' if passed an
@@ -1676,13 +1727,9 @@ minView x = Just $! (first snd $ deleteFindMin x)
16761727
-- > maxView empty == Nothing
16771728

16781729
maxView :: Map k a -> Maybe (a, Map k a)
1679-
maxView Tip = Nothing
1680-
maxView x = Just $! (first snd $ deleteFindMax x)
1681-
1682-
-- Update the 1st component of a tuple (stricter version of
1683-
-- Control.Arrow.first)
1684-
first :: (a -> b) -> (a,c) -> (b,c)
1685-
first f (x,y) = (f x, y)
1730+
maxView t = case maxViewWithKey t of
1731+
Nothing -> Nothing
1732+
Just ((_, x), t') -> Just (x, t')
16861733

16871734
{--------------------------------------------------------------------
16881735
Union.
@@ -3670,39 +3717,48 @@ link2 l@(Bin sizeL kx x lx rx) r@(Bin sizeR ky y ly ry)
36703717
glue :: Map k a -> Map k a -> Map k a
36713718
glue Tip r = r
36723719
glue l Tip = l
3673-
glue l r
3674-
| size l > size r = let ((km,m),l') = deleteFindMax l in balanceR km m l' r
3675-
| otherwise = let ((km,m),r') = deleteFindMin r in balanceL km m l r'
3720+
glue l@(Bin sl kl xl ll lr) r@(Bin sr kr xr rl rr)
3721+
| sl > sr = let !(MaxView km m l') = maxViewSure kl xl ll lr in balanceR km m l' r
3722+
| otherwise = let !(MinView km m r') = minViewSure kr xr rl rr in balanceL km m l r'
3723+
3724+
data MinView k a = MinView !k a !(Map k a)
3725+
data MaxView k a = MaxView !k a !(Map k a)
36763726

3727+
minViewSure :: k -> a -> Map k a -> Map k a -> MinView k a
3728+
minViewSure = go
3729+
where
3730+
go k x Tip r = MinView k x r
3731+
go k x (Bin _ kl xl ll lr) r =
3732+
case go kl xl ll lr of
3733+
MinView km xm l' -> MinView km xm (balanceR k x l' r)
3734+
3735+
maxViewSure :: k -> a -> Map k a -> Map k a -> MaxView k a
3736+
maxViewSure = go
3737+
where
3738+
go k x l Tip = MaxView k x l
3739+
go k x l (Bin _ kr xr rl rr) =
3740+
case go kr xr rl rr of
3741+
MaxView km xm r' -> MaxView km xm (balanceL k x l r')
36773742

36783743
-- | /O(log n)/. Delete and find the minimal element.
36793744
--
36803745
-- > deleteFindMin (fromList [(5,"a"), (3,"b"), (10,"c")]) == ((3,"b"), fromList[(5,"a"), (10,"c")])
36813746
-- > deleteFindMin Error: can not return the minimal element of an empty map
36823747

36833748
deleteFindMin :: Map k a -> ((k,a),Map k a)
3684-
deleteFindMin t
3685-
= case t of
3686-
Bin _ k x Tip r -> ((k,x),r)
3687-
Bin _ k x l r -> let !(km,l') = deleteFindMin l
3688-
!t' = balanceR k x l' r
3689-
in (km, t')
3690-
Tip -> (error "Map.deleteFindMin: can not return the minimal element of an empty map", Tip)
3749+
deleteFindMin t = case minViewWithKey t of
3750+
Nothing -> (error "Map.deleteFindMin: can not return the minimal element of an empty map", Tip)
3751+
Just res -> res
36913752

36923753
-- | /O(log n)/. Delete and find the maximal element.
36933754
--
36943755
-- > deleteFindMax (fromList [(5,"a"), (3,"b"), (10,"c")]) == ((10,"c"), fromList [(3,"b"), (5,"a")])
36953756
-- > deleteFindMax empty Error: can not return the maximal element of an empty map
36963757

36973758
deleteFindMax :: Map k a -> ((k,a),Map k a)
3698-
deleteFindMax t
3699-
= case t of
3700-
Bin _ k x l Tip -> ((k,x),l)
3701-
Bin _ k x l r -> let !(km,r') = deleteFindMax r
3702-
!t' = balanceL k x l r'
3703-
in (km, t')
3704-
Tip -> (error "Map.deleteFindMax: can not return the maximal element of an empty map", Tip)
3705-
3759+
deleteFindMax t = case maxViewWithKey t of
3760+
Nothing -> (error "Map.deleteFindMax: can not return the maximal element of an empty map", Tip)
3761+
Just res -> res
37063762

37073763
{--------------------------------------------------------------------
37083764
[balance l x r] balances two trees with value x.

Data/Map/Lazy.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ module Data.Map.Lazy (
6666
Map -- instance Eq,Show,Read
6767

6868
-- * Operators
69-
, (!), (\\)
69+
, (!), (!?), (\\)
7070

7171
-- * Query
7272
, null
@@ -212,6 +212,8 @@ module Data.Map.Lazy (
212212
, splitAt
213213

214214
-- * Min\/Max
215+
, lookupMin
216+
, lookupMax
215217
, findMin
216218
, findMax
217219
, deleteMin

Data/Map/Strict.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ module Data.Map.Strict
7474
Map -- instance Eq,Show,Read
7575

7676
-- * Operators
77-
, (!), (\\)
77+
, (!), (!?), (\\)
7878

7979
-- * Query
8080
, null
@@ -221,6 +221,8 @@ module Data.Map.Strict
221221
, splitAt
222222

223223
-- * Min\/Max
224+
, lookupMin
225+
, lookupMax
224226
, findMin
225227
, findMax
226228
, deleteMin

Data/Map/Strict/Internal.hs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ module Data.Map.Strict.Internal
8888
Map(..) -- instance Eq,Show,Read
8989

9090
-- * Operators
91-
, (!), (\\)
91+
, (!), (!?), (\\)
9292

9393
-- * Query
9494
, null
@@ -273,6 +273,8 @@ module Data.Map.Strict.Internal
273273
, splitAt
274274

275275
-- * Min\/Max
276+
, lookupMin
277+
, lookupMax
276278
, findMin
277279
, findMax
278280
, deleteMin
@@ -312,6 +314,7 @@ import Data.Map.Internal
312314
, merge
313315
, mergeA
314316
, (!)
317+
, (!?)
315318
, (\\)
316319
, assocs
317320
, atKeyImpl
@@ -363,6 +366,8 @@ import Data.Map.Internal
363366
, lookupIndex
364367
, lookupLE
365368
, lookupLT
369+
, lookupMin
370+
, lookupMax
366371
, mapKeys
367372
, mapKeysMonotonic
368373
, maxView

Data/Set.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ module Data.Set (
121121
, fold
122122

123123
-- * Min\/Max
124+
, lookupMin
125+
, lookupMax
124126
, findMin
125127
, findMax
126128
, deleteMin

0 commit comments

Comments
 (0)