Skip to content

Commit 4fff7c0

Browse files
committed
Make strict IntMap merges strict
* Make `Data.IntMap.Merge.Strict` tactics (except `preserveMissing`) strict. * Add a strict `Data.Map.Merge.Strict` `preserveMissing'` tactic. We may want to just call this `preserveMissing`.... Fixes #609
1 parent 1863928 commit 4fff7c0

File tree

8 files changed

+1326
-896
lines changed

8 files changed

+1326
-896
lines changed

Data/IntMap/Internal.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ module Data.IntMap.Internal (
173173
, map
174174
, mapWithKey
175175
, traverseWithKey
176+
, traverseMaybeWithKey
176177
, mapAccum
177178
, mapAccumWithKey
178179
, mapAccumRWithKey

Data/IntMap/Merge/Strict.hs

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
{-# LANGUAGE DeriveDataTypeable, StandaloneDeriving #-}
55
#endif
66
#if !defined(TESTING) && defined(__GLASGOW_HASKELL__)
7-
{-# LANGUAGE Safe #-}
7+
{-# LANGUAGE Trustworthy #-}
88
#endif
99
#if __GLASGOW_HASKELL__ >= 708
1010
{-# LANGUAGE RoleAnnotations #-}
@@ -98,3 +98,136 @@ module Data.IntMap.Merge.Strict (
9898
) where
9999

100100
import Data.IntMap.Internal
101+
( SimpleWhenMissing
102+
, SimpleWhenMatched
103+
, merge
104+
, dropMissing
105+
, preserveMissing
106+
, filterMissing
107+
, WhenMissing (..)
108+
, WhenMatched (..)
109+
, mergeA
110+
, filterAMissing
111+
, runWhenMatched
112+
, runWhenMissing
113+
)
114+
import Data.IntMap.Strict.Internal
115+
#if !MIN_VERSION_base(4,8,0)
116+
import Control.Applicative (Applicative (..), (<$>))
117+
#endif
118+
import Prelude hiding (filter, map, foldl, foldr)
119+
120+
-- | Map covariantly over a @'WhenMissing' f k x@.
121+
mapWhenMissing :: Functor f => (a -> b) -> WhenMissing f x a -> WhenMissing f x b
122+
mapWhenMissing f q = WhenMissing
123+
{ missingSubtree = fmap (map f) . missingSubtree q
124+
, missingKey = \k x -> fmap (forceMaybe . fmap f) $ missingKey q k x}
125+
126+
-- | Map covariantly over a @'WhenMatched' f k x y@.
127+
mapWhenMatched :: Functor f => (a -> b) -> WhenMatched f x y a -> WhenMatched f x y b
128+
mapWhenMatched f q = WhenMatched
129+
{ matchedKey = \k x y -> fmap (forceMaybe . fmap f) $ runWhenMatched q k x y }
130+
131+
-- | When a key is found in both maps, apply a function to the
132+
-- key and values and maybe use the result in the merged map.
133+
--
134+
-- @
135+
-- zipWithMaybeMatched :: (k -> x -> y -> Maybe z)
136+
-- -> SimpleWhenMatched k x y z
137+
-- @
138+
zipWithMaybeMatched :: Applicative f
139+
=> (Key -> x -> y -> Maybe z)
140+
-> WhenMatched f x y z
141+
zipWithMaybeMatched f = WhenMatched $
142+
\k x y -> pure $! forceMaybe $! f k x y
143+
{-# INLINE zipWithMaybeMatched #-}
144+
145+
-- | When a key is found in both maps, apply a function to the
146+
-- key and values, perform the resulting action, and maybe use
147+
-- the result in the merged map.
148+
--
149+
-- This is the fundamental 'WhenMatched' tactic.
150+
zipWithMaybeAMatched :: Applicative f
151+
=> (Key -> x -> y -> f (Maybe z))
152+
-> WhenMatched f x y z
153+
zipWithMaybeAMatched f = WhenMatched $
154+
\ k x y -> forceMaybe <$> f k x y
155+
{-# INLINE zipWithMaybeAMatched #-}
156+
157+
-- | When a key is found in both maps, apply a function to the
158+
-- key and values to produce an action and use its result in the merged map.
159+
zipWithAMatched :: Applicative f
160+
=> (Key -> x -> y -> f z)
161+
-> WhenMatched f x y z
162+
zipWithAMatched f = WhenMatched $
163+
\ k x y -> (Just $!) <$> f k x y
164+
{-# INLINE zipWithAMatched #-}
165+
166+
-- | When a key is found in both maps, apply a function to the
167+
-- key and values and use the result in the merged map.
168+
--
169+
-- @
170+
-- zipWithMatched :: (k -> x -> y -> z)
171+
-- -> SimpleWhenMatched k x y z
172+
-- @
173+
zipWithMatched :: Applicative f
174+
=> (Key -> x -> y -> z) -> WhenMatched f x y z
175+
zipWithMatched f = WhenMatched $
176+
\k x y -> pure $! Just $! f k x y
177+
{-# INLINE zipWithMatched #-}
178+
179+
-- | Map over the entries whose keys are missing from the other map,
180+
-- optionally removing some. This is the most powerful 'SimpleWhenMissing'
181+
-- tactic, but others are usually more efficient.
182+
--
183+
-- @
184+
-- mapMaybeMissing :: (k -> x -> Maybe y) -> SimpleWhenMissing k x y
185+
-- @
186+
--
187+
-- prop> mapMaybeMissing f = traverseMaybeMissing (\k x -> pure (f k x))
188+
--
189+
-- but @mapMaybeMissing@ uses fewer unnecessary 'Applicative' operations.
190+
mapMaybeMissing :: Applicative f => (Key -> x -> Maybe y) -> WhenMissing f x y
191+
mapMaybeMissing f = WhenMissing
192+
{ missingSubtree = \m -> pure $! mapMaybeWithKey f m
193+
, missingKey = \k x -> pure $! forceMaybe $! f k x }
194+
{-# INLINE mapMaybeMissing #-}
195+
196+
-- | Map over the entries whose keys are missing from the other map.
197+
--
198+
-- @
199+
-- mapMissing :: (k -> x -> y) -> SimpleWhenMissing k x y
200+
-- @
201+
--
202+
-- prop> mapMissing f = mapMaybeMissing (\k x -> Just $ f k x)
203+
--
204+
-- but @mapMissing@ is somewhat faster.
205+
mapMissing :: Applicative f => (Key -> x -> y) -> WhenMissing f x y
206+
mapMissing f = WhenMissing
207+
{ missingSubtree = \m -> pure $! mapWithKey f m
208+
, missingKey = \k x -> pure $! Just $! f k x }
209+
{-# INLINE mapMissing #-}
210+
211+
-- | Traverse over the entries whose keys are missing from the other map,
212+
-- optionally producing values to put in the result.
213+
-- This is the most powerful 'WhenMissing' tactic, but others are usually
214+
-- more efficient.
215+
traverseMaybeMissing :: Applicative f
216+
=> (Key -> x -> f (Maybe y)) -> WhenMissing f x y
217+
traverseMaybeMissing f = WhenMissing
218+
{ missingSubtree = traverseMaybeWithKey f
219+
, missingKey = \k x -> forceMaybe <$> f k x }
220+
{-# INLINE traverseMaybeMissing #-}
221+
222+
-- | Traverse over the entries whose keys are missing from the other map.
223+
traverseMissing :: Applicative f
224+
=> (Key -> x -> f y) -> WhenMissing f x y
225+
traverseMissing f = WhenMissing
226+
{ missingSubtree = traverseWithKey f
227+
, missingKey = \k x -> (Just $!) <$> f k x }
228+
{-# INLINE traverseMissing #-}
229+
230+
forceMaybe :: Maybe a -> Maybe a
231+
forceMaybe Nothing = Nothing
232+
forceMaybe m@(Just !_) = m
233+
{-# INLINE forceMaybe #-}

0 commit comments

Comments
 (0)