@@ -81,10 +81,11 @@ nubOrdOn f = -- Inline with 1 arg
8181nubOrdOnExcluding :: Ord b => (a -> b ) -> Set b -> [a ] -> [a ]
8282nubOrdOnExcluding f = go
8383 where
84- go _ [] = []
85- go s (x: xs) = case tryInsertSet fx s of
84+ go ! _ [] = []
85+ go ! s (x: xs) = case tryInsertSet fx s of
8686 Nothing -> go s xs
87- Just s' -> x : go s' xs
87+ Just ! s' -> -- See Note [Eager set insertions]
88+ x : go s' xs
8889 where ! fx = f x
8990
9091tryInsertSet :: Ord a => a -> Set a -> Maybe (Set a )
@@ -114,15 +115,16 @@ nubOrdOnFB :: Ord b
114115 -> Set b
115116 -> r
116117nubOrdOnFB f c = -- Inline with 2 args
117- \ x r -> oneShot (\ s ->
118+ \ x r -> oneShot (\ ! s ->
118119 let ! y = f x
119120 in case tryInsertSet y s of
120121 Nothing -> r s
121- Just s' -> x `c` r s')
122+ Just ! s' -> -- See Note [Eager set insertions]
123+ x `c` r s')
122124{-# INLINE [0] nubOrdOnFB #-}
123125
124126constNubOn :: a -> b -> a
125- constNubOn x _ = x
127+ constNubOn x ! _ = x
126128{-# INLINE [0] constNubOn #-}
127129#endif
128130
@@ -167,10 +169,12 @@ nubIntOn f = -- Inline with 1 arg
167169nubIntOnExcluding :: (a -> Int ) -> IntSet -> [a ] -> [a ]
168170nubIntOnExcluding f = go
169171 where
170- go _ [] = []
171- go s (x: xs)
172+ go ! _ [] = []
173+ go ! s (x: xs)
172174 | fx `IntSet.member` s = go s xs
173- | otherwise = x : go (IntSet. insert fx s) xs
175+ | otherwise =
176+ let ! s' = IntSet. insert fx s -- See Note [Eager set insertions]
177+ in x : go s' xs
174178 where ! fx = f x
175179
176180#ifdef __GLASGOW_HASKELL__
@@ -194,10 +198,24 @@ nubIntOnFB :: (a -> Int)
194198 -> IntSet
195199 -> r
196200nubIntOnFB f c = -- Inline with 2 args
197- \ x r -> oneShot (\ s ->
201+ \ x r -> oneShot (\ ! s ->
198202 let ! y = f x
199203 in if y `IntSet.member` s
200204 then r s
201- else x `c` r (IntSet. insert y s))
205+ else let ! s' = IntSet. insert y s -- See Note [Eager set insertions]
206+ in x `c` r s')
202207{-# INLINE [0] nubIntOnFB #-}
203208#endif
209+
210+ -- Note [Eager set insertions]
211+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~
212+ --
213+ -- In nubOrd and nubInt we insert new elements into the set eagerly. This means
214+ -- that we perform a bit of work before we yield the current element which is
215+ -- not strictly necessary.
216+ --
217+ -- The lazier option would be to create a thunk for the new set, which would get
218+ -- forced by the membership check in the next step. However, a thunk has a small
219+ -- overhead, and the small costs of thunks at every step adds up to a noticeable
220+ -- amount of time and allocations overall. So, we avoid this and perform the
221+ -- insertions eagerly instead.
0 commit comments