on master help sign in
Rewrite mapAccumL to be fast
3e619a5Bryan O'Sullivan
Data/Text.hs+2−7
@@ -781,16 +781,11 @@ scanr1 f t | null t = empty
781 | otherwise = scanr f (last t) (init t)
781 | otherwise = scanr f (last t) (init t)
782{-# INLINE scanr1 #-}
782{-# INLINE scanr1 #-}
783
783
784−-- | /O(n)/ Like a combination of 'map' and 'foldl'. Applies a
784+-- | /O(n)/ Like a combination of 'map' and 'foldl''. Applies a
785-- function to each element of a 'Text', passing an accumulating
785-- function to each element of a 'Text', passing an accumulating
786-- parameter from left to right, and returns a final 'Text'.
786-- parameter from left to right, and returns a final 'Text'.
787mapAccumL :: (a -> Char -> (a,Char)) -> a -> Text -> (a, Text)
787mapAccumL :: (a -> Char -> (a,Char)) -> a -> Text -> (a, Text)
788−mapAccumL f = go
788+mapAccumL f z0 = S.mapAccumL f z0 . stream
789− where go s t = case uncons t of
790− Nothing -> (s, empty)
791− Just (x, xs) -> (s'', cons y ys)
792− where (s', y ) = f s x
793− (s'',ys) = go s' xs
794{-# INLINE mapAccumL #-}
789{-# INLINE mapAccumL #-}
795
790
796-- | The 'mapAccumR' function behaves like a combination of 'map' and
791-- | The 'mapAccumR' function behaves like a combination of 'map' and
Data/Text/Fusion.hs+30
@@ -34,6 +34,9 @@ module Data.Text.Fusion
34 -- ** Scans
34 -- ** Scans
35 , reverseScanr
35 , reverseScanr
36
36
37+ -- ** Accumulating maps
38+ , mapAccumL
39+
37 -- ** Generation and unfolding
40 -- ** Generation and unfolding
38 , unfoldrN
41 , unfoldrN
39
42
@@ -199,3 +202,30 @@ findIndex = S.findIndexI
199countChar :: Char -> Stream Char -> Int
202countChar :: Char -> Stream Char -> Int
200countChar = S.countCharI
203countChar = S.countCharI
201{-# INLINE [0] countChar #-}
204{-# INLINE [0] countChar #-}
205+
206+-- | /O(n)/ Like a combination of 'map' and 'foldl''. Applies a
207+-- function to each element of a 'Text', passing an accumulating
208+-- parameter from left to right, and returns a final 'Text'.
209+mapAccumL :: (a -> Char -> (a,Char)) -> a -> Stream Char -> (a, Text)
210+mapAccumL f z0 (Stream next0 s0 len) = (nz,I.textP na 0 nl)
211+ where
212+ (na,(nz,nl)) = A.run2 (A.unsafeNew mlen >>= \arr -> outer arr mlen z0 s0 0)
213+ where mlen = upperBound 4 len
214+ outer arr top = loop
215+ where
216+ loop !z !s !i =
217+ case next0 s of
218+ Done -> return (arr, (z,i))
219+ Skip s' -> loop z s' i
220+ Yield x s'
221+ | j >= top -> {-# SCC "mapAccumL/resize" #-} do
222+ let top' = (top + 1) `shiftL` 1
223+ arr' <- A.unsafeNew top'
224+ A.copyM arr' 0 arr 0 top
225+ outer arr' top' z s i
226+ | otherwise -> do let (z',c) = f z x
227+ d <- unsafeWrite arr i c
228+ loop z' s' (i+d)
229+ where j | ord x < 0x10000 = i
230+ | otherwise = i + 1
231+{-# INLINE [0] mapAccumL #-}
tests/benchmarks/StripBrackets.hsnew file+21
@@ -0,0 +1,21 @@
1+-- From Petr Prokhorenkov.
2+
3+import Data.Text as T
4+import Data.Text.IO as T
5+
6+stripBrackets :: T.Text -> T.Text
7+stripBrackets text = snd $ T.mapAccumL f 0 text where
8+ f depth c = let
9+ depth' = depth + d' c
10+ c' | depth > 0 || depth' > 0 = ' '
11+ | otherwise = c
12+ in
13+ (depth', c')
14+
15+ d' '{' = 1
16+ d' '[' = 1
17+ d' '}' = -1
18+ d' ']' = -1
19+ d' _ = 0
20+
21+main = T.interact stripBrackets