on master help sign in
Implement and test lazy zipWith
d4acc5eBryan O'Sullivan
Data/Text.hs+2−1
@@ -820,7 +820,7 @@ filter p t = unstream (S.filter p (stream t))
820-------------------------------------------------------------------------------
820-------------------------------------------------------------------------------
821-- ** Indexing 'Text's
821-- ** Indexing 'Text's
822
822
823−-- | /O(1)/ 'Text' index (subscript) operator, starting from 0.
823+-- | /O(n)/ 'Text' index (subscript) operator, starting from 0.
824index :: Text -> Int -> Char
824index :: Text -> Int -> Char
825index t n = S.index (stream t) n
825index t n = S.index (stream t) n
826{-# INLINE index #-}
826{-# INLINE index #-}
@@ -868,6 +868,7 @@ count c t = S.count c (stream t)
868-- given as the first argument, instead of a tupling function.
868-- given as the first argument, instead of a tupling function.
869zipWith :: (Char -> Char -> Char) -> Text -> Text -> Text
869zipWith :: (Char -> Char -> Char) -> Text -> Text -> Text
870zipWith f t1 t2 = unstream (S.zipWith f (stream t1) (stream t2))
870zipWith f t1 t2 = unstream (S.zipWith f (stream t1) (stream t2))
871+{-# INLINE [0] zipWith #-}
871
872
872-- | /O(n)/ Breaks a 'Text' up into a list of words, delimited by 'Char's
873-- | /O(n)/ Breaks a 'Text' up into a list of words, delimited by 'Char's
873-- representing white space.
874-- representing white space.
Data/Text/Fusion.hs+3−14
@@ -48,7 +48,7 @@ module Data.Text.Fusion
48 ) where
48 ) where
49
49
50import Prelude (Bool(..), Char, Eq(..), Maybe(..), Monad(..), Int,
50import Prelude (Bool(..), Char, Eq(..), Maybe(..), Monad(..), Int,
51− Num(..), Ord(..), String, ($), (++), (&&),
51+ Num(..), Ord(..), ($), (&&),
52 fromIntegral, otherwise)
52 fromIntegral, otherwise)
53import Data.Bits ((.&.), shiftR)
53import Data.Bits ((.&.), shiftR)
54import Data.Char (ord)
54import Data.Char (ord)
@@ -181,17 +181,9 @@ unfoldrN n = S.unfoldrNI n
181-------------------------------------------------------------------------------
181-------------------------------------------------------------------------------
182-- ** Indexing streams
182-- ** Indexing streams
183
183
184−-- | /O(1)/ stream index (subscript) operator, starting from 0.
184+-- | /O(n)/ stream index (subscript) operator, starting from 0.
185index :: Stream Char -> Int -> Char
185index :: Stream Char -> Int -> Char
186−index (Stream next s0 _len) n0
186+index = S.indexI
187− | n0 < 0 = streamError "index" "Negative index"
188− | otherwise = loop_index n0 s0
189− where
190− loop_index !n !s = case next s of
191− Done -> streamError "index" "Index too large"
192− Skip s' -> loop_index n s'
193− Yield x s' | n == 0 -> x
194− | otherwise -> loop_index (n-1) s'
195{-# INLINE [0] index #-}
187{-# INLINE [0] index #-}
196
188
197-- | The 'findIndex' function takes a predicate and a stream and
189-- | The 'findIndex' function takes a predicate and a stream and
@@ -261,6 +253,3 @@ count a (Stream next s0 _len) = loop 0 s0
261 Yield x s' | a == x -> loop (i+1) s'
253 Yield x s' | a == x -> loop (i+1) s'
262 | otherwise -> loop i s'
254 | otherwise -> loop i s'
263{-# INLINE [0] count #-}
255{-# INLINE [0] count #-}
264−
265−streamError :: String -> String -> a
266−streamError func msg = P.error $ "Data.Text.Fusion." ++ func ++ ": " ++ msg
Data/Text/Fusion/Common.hs+14
@@ -79,6 +79,7 @@ module Data.Text.Fusion.Common
79
79
80 -- * Indexing
80 -- * Indexing
81 , find
81 , find
82+ , indexI
82
83
83 -- * Zipping and unzipping
84 -- * Zipping and unzipping
84 , zipWith
85 , zipWith
@@ -635,6 +636,19 @@ find p (Stream next s0 _len) = loop_find s0
635 | otherwise -> loop_find s'
636 | otherwise -> loop_find s'
636{-# INLINE [0] find #-}
637{-# INLINE [0] find #-}
637
638
639+-- | /O(n)/ Stream index (subscript) operator, starting from 0.
640+indexI :: Integral a => Stream Char -> a -> Char
641+indexI (Stream next s0 _len) n0
642+ | n0 < 0 = streamError "index" "Negative index"
643+ | otherwise = loop_index n0 s0
644+ where
645+ loop_index !n !s = case next s of
646+ Done -> streamError "index" "Index too large"
647+ Skip s' -> loop_index n s'
648+ Yield x s' | n == 0 -> x
649+ | otherwise -> loop_index (n-1) s'
650+{-# INLINE [0] indexI #-}
651+
638-- | /O(n)/ 'filter', applied to a predicate and a stream,
652-- | /O(n)/ 'filter', applied to a predicate and a stream,
639-- returns a stream containing those characters that satisfy the
653-- returns a stream containing those characters that satisfy the
640-- predicate.
654-- predicate.
Data/Text/Lazy.hs+13−2
@@ -133,7 +133,7 @@ module Data.Text.Lazy
133 -- , findSubstring
133 -- , findSubstring
134
134
135 -- * Indexing
135 -- * Indexing
136− -- , index
136+ , index
137 -- , findIndex
137 -- , findIndex
138 -- , findIndices
138 -- , findIndices
139 -- , elemIndex
139 -- , elemIndex
@@ -141,7 +141,7 @@ module Data.Text.Lazy
141 -- , count
141 -- , count
142
142
143 -- * Zipping and unzipping
143 -- * Zipping and unzipping
144− -- , zipWith
144+ , zipWith
145
145
146 -- -* Ordered text
146 -- -* Ordered text
147 -- , sort
147 -- , sort
@@ -809,6 +809,17 @@ partition :: (Char -> Bool) -> Text -> (Text, Text)
809partition p t = (filter p t, filter (not . p) t)
809partition p t = (filter p t, filter (not . p) t)
810{-# INLINE partition #-}
810{-# INLINE partition #-}
811
811
812+-- | /O(n)/ 'Text' index (subscript) operator, starting from 0.
813+index :: Text -> Int64 -> Char
814+index t n = S.index (stream t) n
815+{-# INLINE index #-}
816+
817+-- | /O(n)/ 'zipWith' generalises 'zip' by zipping with the function
818+-- given as the first argument, instead of a tupling function.
819+zipWith :: (Char -> Char -> Char) -> Text -> Text -> Text
820+zipWith f t1 t2 = unstream (S.zipWith f (stream t1) (stream t2))
821+{-# INLINE [0] zipWith #-}
822+
812revChunks :: [T.Text] -> Text
823revChunks :: [T.Text] -> Text
813revChunks = L.foldl' (flip chunk) Empty
824revChunks = L.foldl' (flip chunk) Empty
814
825
Data/Text/Lazy/Fusion.hs+6
@@ -17,6 +17,7 @@ module Data.Text.Lazy.Fusion
17 , unstreamChunks
17 , unstreamChunks
18 , length
18 , length
19 , unfoldrN
19 , unfoldrN
20+ , index
20 ) where
21 ) where
21
22
22import Prelude hiding (length)
23import Prelude hiding (length)
@@ -93,3 +94,8 @@ length = S.lengthI
93unfoldrN :: Int64 -> (a -> Maybe (Char,a)) -> a -> Stream Char
94unfoldrN :: Int64 -> (a -> Maybe (Char,a)) -> a -> Stream Char
94unfoldrN n = S.unfoldrNI n
95unfoldrN n = S.unfoldrNI n
95{-# INLINE [0] unfoldrN #-}
96{-# INLINE [0] unfoldrN #-}
97+
98+-- | /O(n)/ stream index (subscript) operator, starting from 0.
99+index :: Stream Char -> Int64 -> Char
100+index = S.indexI
101+{-# INLINE [0] index #-}
tests/Properties.hs+3−1
@@ -318,13 +318,14 @@ prop_T_partition p = L.partition p `eqP` (unpack2 . T.partition p)
318prop_TL_partition p = L.partition p `eqP` (unpack2 . TL.partition p)
318prop_TL_partition p = L.partition p `eqP` (unpack2 . TL.partition p)
319
319
320prop_T_index x s = x < L.length s && x >= 0 ==>
320prop_T_index x s = x < L.length s && x >= 0 ==>
321− (L.!!) s x == T.index (packT s) x
321+ (L.!!) s x == T.index (packT s) x
322prop_T_findIndex p = L.findIndex p `eqP` T.findIndex p
322prop_T_findIndex p = L.findIndex p `eqP` T.findIndex p
323prop_T_findIndices p = L.findIndices p`eqP` T.findIndices p
323prop_T_findIndices p = L.findIndices p`eqP` T.findIndices p
324prop_T_elemIndex c = L.elemIndex c `eqP` T.elemIndex c
324prop_T_elemIndex c = L.elemIndex c `eqP` T.elemIndex c
325prop_T_elemIndices c = L.elemIndices c`eqP` T.elemIndices c
325prop_T_elemIndices c = L.elemIndices c`eqP` T.elemIndices c
326prop_T_count c = (L.length . L.elemIndices c) `eqP` T.count c
326prop_T_count c = (L.length . L.elemIndices c) `eqP` T.count c
327prop_T_zipWith c s = L.zipWith c s `eqP` (unpackT . T.zipWith c (packT s))
327prop_T_zipWith c s = L.zipWith c s `eqP` (unpackT . T.zipWith c (packT s))
328+prop_TL_zipWith c s = L.zipWith c s `eqP` (unpackT . TL.zipWith c (packT s))
328
329
329-- Regression tests.
330-- Regression tests.
330prop_S_filter_eq s = S.filter p t == S.streamList (filter p s)
331prop_S_filter_eq s = S.filter p t == S.streamList (filter p s)
@@ -527,6 +528,7 @@ tests = [
527 ("prop_T_elemIndices", mytest prop_T_elemIndices),
528 ("prop_T_elemIndices", mytest prop_T_elemIndices),
528 ("prop_T_count", mytest prop_T_count),
529 ("prop_T_count", mytest prop_T_count),
529 ("prop_T_zipWith", mytest prop_T_zipWith),
530 ("prop_T_zipWith", mytest prop_T_zipWith),
531+ ("prop_TL_zipWith", mytest prop_TL_zipWith),
530
532
531 ("prop_S_filter_eq", mytest prop_S_filter_eq)
533 ("prop_S_filter_eq", mytest prop_S_filter_eq)
532 ]
534 ]