@@ -326,7 +326,7 @@ import Data.Bits
326
326
import qualified Data.Foldable as Foldable
327
327
import Data.Maybe (fromMaybe )
328
328
import Utils.Containers.Internal.Prelude hiding
329
- (lookup , map , filter , foldr , foldl , foldl' , null )
329
+ (lookup , map , filter , foldr , foldl , foldl' , foldMap , null )
330
330
import Prelude ()
331
331
332
332
import Data.IntSet.Internal (IntSet )
@@ -470,23 +470,13 @@ instance Semigroup (IntMap a) where
470
470
471
471
-- | Folds in order of increasing key.
472
472
instance Foldable. Foldable IntMap where
473
- fold = go
474
- where go Nil = mempty
475
- go (Tip _ v) = v
476
- go (Bin p l r)
477
- | signBranch p = go r `mappend` go l
478
- | otherwise = go l `mappend` go r
473
+ fold = foldMap id
479
474
{-# INLINABLE fold #-}
480
475
foldr = foldr
481
476
{-# INLINE foldr #-}
482
477
foldl = foldl
483
478
{-# INLINE foldl #-}
484
- foldMap f t = go t
485
- where go Nil = mempty
486
- go (Tip _ v) = f v
487
- go (Bin p l r)
488
- | signBranch p = go r `mappend` go l
489
- | otherwise = go l `mappend` go r
479
+ foldMap = foldMap
490
480
{-# INLINE foldMap #-}
491
481
foldl' = foldl'
492
482
{-# INLINE foldl' #-}
@@ -3033,31 +3023,37 @@ splitLookup k t =
3033
3023
--
3034
3024
-- > let f a len = len + (length a)
3035
3025
-- > foldr f 0 (fromList [(5,"a"), (3,"bbb")]) == 4
3026
+
3027
+ -- See Note [IntMap folds]
3036
3028
foldr :: (a -> b -> b ) -> b -> IntMap a -> b
3037
3029
foldr f z = \ t -> -- Use lambda t to be inlinable with two arguments only.
3038
3030
case t of
3031
+ Nil -> z
3039
3032
Bin p l r
3040
3033
| signBranch p -> go (go z l) r -- put negative numbers before
3041
3034
| otherwise -> go (go z r) l
3042
3035
_ -> go z t
3043
3036
where
3044
- go z' Nil = z'
3037
+ go _ Nil = error " foldr.go: Nil "
3045
3038
go z' (Tip _ x) = f x z'
3046
3039
go z' (Bin _ l r) = go (go z' r) l
3047
3040
{-# INLINE foldr #-}
3048
3041
3049
3042
-- | \(O(n)\). A strict version of 'foldr'. Each application of the operator is
3050
3043
-- evaluated before using the result in the next application. This
3051
3044
-- function is strict in the starting value.
3045
+
3046
+ -- See Note [IntMap folds]
3052
3047
foldr' :: (a -> b -> b ) -> b -> IntMap a -> b
3053
3048
foldr' f z = \ t -> -- Use lambda t to be inlinable with two arguments only.
3054
3049
case t of
3050
+ Nil -> z
3055
3051
Bin p l r
3056
3052
| signBranch p -> go (go z l) r -- put negative numbers before
3057
3053
| otherwise -> go (go z r) l
3058
3054
_ -> go z t
3059
3055
where
3060
- go ! z' Nil = z'
3056
+ go ! _ Nil = error " foldr'.go: Nil "
3061
3057
go z' (Tip _ x) = f x z'
3062
3058
go z' (Bin _ l r) = go (go z' r) l
3063
3059
{-# INLINE foldr' #-}
@@ -3071,35 +3067,65 @@ foldr' f z = \t -> -- Use lambda t to be inlinable with two arguments only.
3071
3067
--
3072
3068
-- > let f len a = len + (length a)
3073
3069
-- > foldl f 0 (fromList [(5,"a"), (3,"bbb")]) == 4
3070
+
3071
+ -- See Note [IntMap folds]
3074
3072
foldl :: (a -> b -> a ) -> a -> IntMap b -> a
3075
3073
foldl f z = \ t -> -- Use lambda t to be inlinable with two arguments only.
3076
3074
case t of
3075
+ Nil -> z
3077
3076
Bin p l r
3078
3077
| signBranch p -> go (go z r) l -- put negative numbers before
3079
3078
| otherwise -> go (go z l) r
3080
3079
_ -> go z t
3081
3080
where
3082
- go z' Nil = z'
3081
+ go _ Nil = error " foldl.go: Nil "
3083
3082
go z' (Tip _ x) = f z' x
3084
3083
go z' (Bin _ l r) = go (go z' l) r
3085
3084
{-# INLINE foldl #-}
3086
3085
3087
3086
-- | \(O(n)\). A strict version of 'foldl'. Each application of the operator is
3088
3087
-- evaluated before using the result in the next application. This
3089
3088
-- function is strict in the starting value.
3089
+
3090
+ -- See Note [IntMap folds]
3090
3091
foldl' :: (a -> b -> a ) -> a -> IntMap b -> a
3091
3092
foldl' f z = \ t -> -- Use lambda t to be inlinable with two arguments only.
3092
3093
case t of
3094
+ Nil -> z
3093
3095
Bin p l r
3094
3096
| signBranch p -> go (go z r) l -- put negative numbers before
3095
3097
| otherwise -> go (go z l) r
3096
3098
_ -> go z t
3097
3099
where
3098
- go ! z' Nil = z'
3100
+ go ! _ Nil = error " foldl'.go: Nil "
3099
3101
go z' (Tip _ x) = f z' x
3100
3102
go z' (Bin _ l r) = go (go z' l) r
3101
3103
{-# INLINE foldl' #-}
3102
3104
3105
+ -- See Note [IntMap folds]
3106
+ foldMap :: Monoid m => (a -> m ) -> IntMap a -> m
3107
+ foldMap f = \ t -> -- Use lambda to be inlinable with two arguments.
3108
+ case t of
3109
+ Nil -> mempty
3110
+ Bin p l r
3111
+ #if MIN_VERSION_base(4,11,0)
3112
+ | signBranch p -> go r <> go l
3113
+ | otherwise -> go l <> go r
3114
+ #else
3115
+ | signBranch p -> go r `mappend` go l
3116
+ | otherwise -> go l `mappend` go r
3117
+ #endif
3118
+ _ -> go t
3119
+ where
3120
+ go Nil = error " foldMap.go: Nil"
3121
+ go (Tip _ x) = f x
3122
+ #if MIN_VERSION_base(4,11,0)
3123
+ go (Bin _ l r) = go l <> go r
3124
+ #else
3125
+ go (Bin _ l r) = go l `mappend` go r
3126
+ #endif
3127
+ {-# INLINE foldMap #-}
3128
+
3103
3129
-- | \(O(n)\). Fold the keys and values in the map using the given right-associative
3104
3130
-- binary operator, such that
3105
3131
-- @'foldrWithKey' f z == 'Prelude.foldr' ('uncurry' f) z . 'toAscList'@.
@@ -3110,31 +3136,37 @@ foldl' f z = \t -> -- Use lambda t to be inlinable with two arguments only.
3110
3136
--
3111
3137
-- > let f k a result = result ++ "(" ++ (show k) ++ ":" ++ a ++ ")"
3112
3138
-- > foldrWithKey f "Map: " (fromList [(5,"a"), (3,"b")]) == "Map: (5:a)(3:b)"
3139
+
3140
+ -- See Note [IntMap folds]
3113
3141
foldrWithKey :: (Key -> a -> b -> b ) -> b -> IntMap a -> b
3114
3142
foldrWithKey f z = \ t -> -- Use lambda t to be inlinable with two arguments only.
3115
3143
case t of
3144
+ Nil -> z
3116
3145
Bin p l r
3117
3146
| signBranch p -> go (go z l) r -- put negative numbers before
3118
3147
| otherwise -> go (go z r) l
3119
3148
_ -> go z t
3120
3149
where
3121
- go z' Nil = z'
3150
+ go _ Nil = error " foldrWithKey.go: Nil "
3122
3151
go z' (Tip kx x) = f kx x z'
3123
3152
go z' (Bin _ l r) = go (go z' r) l
3124
3153
{-# INLINE foldrWithKey #-}
3125
3154
3126
3155
-- | \(O(n)\). A strict version of 'foldrWithKey'. Each application of the operator is
3127
3156
-- evaluated before using the result in the next application. This
3128
3157
-- function is strict in the starting value.
3158
+
3159
+ -- See Note [IntMap folds]
3129
3160
foldrWithKey' :: (Key -> a -> b -> b ) -> b -> IntMap a -> b
3130
3161
foldrWithKey' f z = \ t -> -- Use lambda t to be inlinable with two arguments only.
3131
3162
case t of
3163
+ Nil -> z
3132
3164
Bin p l r
3133
3165
| signBranch p -> go (go z l) r -- put negative numbers before
3134
3166
| otherwise -> go (go z r) l
3135
3167
_ -> go z t
3136
3168
where
3137
- go ! z' Nil = z'
3169
+ go ! _ Nil = error " foldrWithKey'.go: Nil "
3138
3170
go z' (Tip kx x) = f kx x z'
3139
3171
go z' (Bin _ l r) = go (go z' r) l
3140
3172
{-# INLINE foldrWithKey' #-}
@@ -3149,31 +3181,37 @@ foldrWithKey' f z = \t -> -- Use lambda t to be inlinable with two argument
3149
3181
--
3150
3182
-- > let f result k a = result ++ "(" ++ (show k) ++ ":" ++ a ++ ")"
3151
3183
-- > foldlWithKey f "Map: " (fromList [(5,"a"), (3,"b")]) == "Map: (3:b)(5:a)"
3184
+
3185
+ -- See Note [IntMap folds]
3152
3186
foldlWithKey :: (a -> Key -> b -> a ) -> a -> IntMap b -> a
3153
3187
foldlWithKey f z = \ t -> -- Use lambda t to be inlinable with two arguments only.
3154
3188
case t of
3189
+ Nil -> z
3155
3190
Bin p l r
3156
3191
| signBranch p -> go (go z r) l -- put negative numbers before
3157
3192
| otherwise -> go (go z l) r
3158
3193
_ -> go z t
3159
3194
where
3160
- go z' Nil = z'
3195
+ go _ Nil = error " foldlWithKey.go: Nil "
3161
3196
go z' (Tip kx x) = f z' kx x
3162
3197
go z' (Bin _ l r) = go (go z' l) r
3163
3198
{-# INLINE foldlWithKey #-}
3164
3199
3165
3200
-- | \(O(n)\). A strict version of 'foldlWithKey'. Each application of the operator is
3166
3201
-- evaluated before using the result in the next application. This
3167
3202
-- function is strict in the starting value.
3203
+
3204
+ -- See Note [IntMap folds]
3168
3205
foldlWithKey' :: (a -> Key -> b -> a ) -> a -> IntMap b -> a
3169
3206
foldlWithKey' f z = \ t -> -- Use lambda t to be inlinable with two arguments only.
3170
3207
case t of
3208
+ Nil -> z
3171
3209
Bin p l r
3172
3210
| signBranch p -> go (go z r) l -- put negative numbers before
3173
3211
| otherwise -> go (go z l) r
3174
3212
_ -> go z t
3175
3213
where
3176
- go ! z' Nil = z'
3214
+ go ! _ Nil = error " foldlWithKey'.go: Nil "
3177
3215
go z' (Tip kx x) = f z' kx x
3178
3216
go z' (Bin _ l r) = go (go z' l) r
3179
3217
{-# INLINE foldlWithKey' #-}
@@ -3185,14 +3223,29 @@ foldlWithKey' f z = \t -> -- Use lambda t to be inlinable with two argument
3185
3223
-- This can be an asymptotically faster than 'foldrWithKey' or 'foldlWithKey' for some monoids.
3186
3224
--
3187
3225
-- @since 0.5.4
3226
+
3227
+ -- See Note [IntMap folds]
3188
3228
foldMapWithKey :: Monoid m => (Key -> a -> m ) -> IntMap a -> m
3189
- foldMapWithKey f = go
3229
+ foldMapWithKey f = \ t -> -- Use lambda to be inlinable with two arguments.
3230
+ case t of
3231
+ Nil -> mempty
3232
+ Bin p l r
3233
+ #if MIN_VERSION_base(4,11,0)
3234
+ | signBranch p -> go r <> go l
3235
+ | otherwise -> go l <> go r
3236
+ #else
3237
+ | signBranch p -> go r `mappend` go l
3238
+ | otherwise -> go l `mappend` go r
3239
+ #endif
3240
+ _ -> go t
3190
3241
where
3191
- go Nil = mempty
3192
- go (Tip kx x) = f kx x
3193
- go (Bin p l r)
3194
- | signBranch p = go r `mappend` go l
3195
- | otherwise = go l `mappend` go r
3242
+ go Nil = error " foldMap.go: Nil"
3243
+ go (Tip kx x) = f kx x
3244
+ #if MIN_VERSION_base(4,11,0)
3245
+ go (Bin _ l r) = go l <> go r
3246
+ #else
3247
+ go (Bin _ l r) = go l `mappend` go r
3248
+ #endif
3196
3249
{-# INLINE foldMapWithKey #-}
3197
3250
3198
3251
{- -------------------------------------------------------------------
@@ -4069,3 +4122,40 @@ withEmpty bars = " ":bars
4069
4122
--
4070
4123
-- The implementation is defined as a foldl' over the input list, which makes
4071
4124
-- it a good consumer in list fusion.
4125
+
4126
+ -- Note [IntMap folds]
4127
+ -- ~~~~~~~~~~~~~~~~~~~
4128
+ -- Folds on IntMap are defined in a particular way for a few reasons.
4129
+ --
4130
+ -- foldl' :: (a -> b -> a) -> a -> IntMap b -> a
4131
+ -- foldl' f z = \t ->
4132
+ -- case t of
4133
+ -- Nil -> z
4134
+ -- Bin p l r
4135
+ -- | signBranch p -> go (go z r) l
4136
+ -- | otherwise -> go (go z l) r
4137
+ -- _ -> go z t
4138
+ -- where
4139
+ -- go !_ Nil = error "foldl'.go: Nil"
4140
+ -- go z' (Tip _ x) = f z' x
4141
+ -- go z' (Bin _ l r) = go (go z' l) r
4142
+ -- {-# INLINE foldl' #-}
4143
+ --
4144
+ -- 1. We first check if the Bin separates negative and positive keys, and fold
4145
+ -- over the children accordingly. This check is not inside `go` because it
4146
+ -- can only happen at the top level and we don't need to check every Bin.
4147
+ -- 2. We also check for Nil at the top level instead of, say, `go z Nil = z`.
4148
+ -- That's because `Nil` is also allowed only at the top-level, but more
4149
+ -- importantly it allows for better optimizations if the `Nil` branch errors
4150
+ -- in `go`. For example, if we have
4151
+ -- maximum :: Ord a => IntMap a -> Maybe a
4152
+ -- maximum = foldl' (\m x -> Just $! maybe x (max x) m) Nothing
4153
+ -- because `go` certainly returns a `Just` (or errors), CPR analysis will
4154
+ -- optimize it to return `(# a #)` instead of `Maybe a`. This makes it
4155
+ -- satisfy the conditions for SpecConstr, which generates two specializations
4156
+ -- of `go` for `Nothing` and `Just` inputs. Now both `Maybe`s have been
4157
+ -- optimized out of `go`.
4158
+ -- 3. The `Tip` is not matched on at the top-level to avoid using `f` more than
4159
+ -- once. This allows `f` to be inlined into `go` even if `f` is big, since
4160
+ -- it's likely to be the only place `f` is used, and not inlining `f` means
4161
+ -- missing out on optimizations. See GHC #25259 for more on this.
0 commit comments