on master help sign in
Implement and test unfolds
82875b9Bryan O'Sullivan
Data/Text/Fusion.hs+24−5
@@ -75,6 +75,7 @@ module Data.Text.Fusion
75 , replicate
75 , replicate
76 , unfoldr
76 , unfoldr
77 , unfoldrN
77 , unfoldrN
78+ , unfoldrN64
78
79
79 -- * Substrings
80 -- * Substrings
80 -- ** Breaking strings
81 -- ** Breaking strings
@@ -104,8 +105,8 @@ module Data.Text.Fusion
104 , zipWith
105 , zipWith
105 ) where
106 ) where
106
107
107−import Prelude (Bool(..), Char, Either(..), Eq(..), Maybe(..), Monad(..),
108+import Prelude (Bool(..), Char, Either(..), Eq(..), Integral, Maybe(..),
108− Num(..), Ord(..), String, ($), (++), (.), (&&),
109+ Monad(..), Num(..), Ord(..), String, ($), (++), (.), (&&),
109 fromIntegral, otherwise)
110 fromIntegral, otherwise)
110import qualified Data.List as L
111import qualified Data.List as L
111import GHC.Exts (Int(..), (+#))
112import GHC.Exts (Int(..), (+#))
@@ -641,15 +642,33 @@ unfoldr f s0 = Stream next s0 1
641-- value. However, the length of the result is limited by the
642-- value. However, the length of the result is limited by the
642-- first argument to 'unfoldrN'. This function is more efficient than
643-- first argument to 'unfoldrN'. This function is more efficient than
643-- 'unfoldr' when the length of the result is known.
644-- 'unfoldr' when the length of the result is known.
644−unfoldrN :: Int -> (a -> Maybe (Char,a)) -> a -> Stream Char
645+unfoldrI :: Integral a => a -> (b -> Maybe (Char,b)) -> b -> Stream Char
645−unfoldrN n f s0 | n < 0 = empty
646+unfoldrI n f s0 | n < 0 = empty
646− | otherwise = Stream next (0 :!: s0) (n*2)
647+ | otherwise = Stream next (0 :!: s0) (fromIntegral (n*2))
647 where
648 where
648 {-# INLINE next #-}
649 {-# INLINE next #-}
649 next (z :!: s) = case f s of
650 next (z :!: s) = case f s of
650 Nothing -> Done
651 Nothing -> Done
651 Just (w, s') | z >= n -> Done
652 Just (w, s') | z >= n -> Done
652 | otherwise -> Yield w ((z + 1) :!: s')
653 | otherwise -> Yield w ((z + 1) :!: s')
654+{-# INLINE unfoldrI #-}
655+
656+-- | /O(n)/ Like 'unfoldr', 'unfoldrN' builds a stream from a seed
657+-- value. However, the length of the result is limited by the
658+-- first argument to 'unfoldrN'. This function is more efficient than
659+-- 'unfoldr' when the length of the result is known.
660+unfoldrN :: Int -> (a -> Maybe (Char,a)) -> a -> Stream Char
661+unfoldrN n = unfoldrI (fromIntegral n :: Int)
662+{-# INLINE [0] unfoldrN #-}
663+
664+-- | /O(n)/ Like 'unfoldr', 'unfoldrN64' builds a stream from a seed
665+-- value. However, the length of the result is limited by the
666+-- first argument to 'unfoldrN64'. This function is more efficient than
667+-- 'unfoldr' when the length of the result is known.
668+unfoldrN64 :: Int64 -> (a -> Maybe (Char,a)) -> a -> Stream Char
669+unfoldrN64 n = unfoldrI (fromIntegral n :: Int64)
670+{-# INLINE [0] unfoldrN64 #-}
671+
653-------------------------------------------------------------------------------
672-------------------------------------------------------------------------------
654-- * Substreams
673-- * Substreams
655
674
Data/Text/Lazy.hs+28−3
@@ -87,9 +87,9 @@ module Data.Text.Lazy
87 , mapAccumR
87 , mapAccumR
88
88
89 -- ** Generation and unfolding
89 -- ** Generation and unfolding
90− -- , replicate
90+ , replicate
91− -- , unfoldr
91+ , unfoldr
92− -- , unfoldrN
92+ , unfoldrN
93
93
94 -- * Substrings
94 -- * Substrings
95
95
@@ -468,6 +468,31 @@ mapAccumR f s t = case uncons t of
468 where (s'',y ) = f s' x
468 where (s'',y ) = f s' x
469 (s', ys) = mapAccumR f s xs
469 (s', ys) = mapAccumR f s xs
470
470
471+-- | /O(n)/ 'replicate' @n@ @c@ is a 'Text' of length @n@ with @c@ the
472+-- value of every element.
473+replicate :: Int -> Char -> Text
474+replicate n c = unstream (S.replicate n c)
475+{-# INLINE replicate #-}
476+
477+-- | /O(n)/, where @n@ is the length of the result. The 'unfoldr'
478+-- function is analogous to the List 'L.unfoldr'. 'unfoldr' builds a
479+-- 'Text' from a seed value. The function takes the element and
480+-- returns 'Nothing' if it is done producing the 'Text', otherwise
481+-- 'Just' @(a,b)@. In this case, @a@ is the next 'Char' in the
482+-- string, and @b@ is the seed value for further production.
483+unfoldr :: (a -> Maybe (Char,a)) -> a -> Text
484+unfoldr f s = unstream (S.unfoldr f s)
485+{-# INLINE unfoldr #-}
486+
487+-- | /O(n)/ Like 'unfoldr', 'unfoldrN' builds a 'Text' from a seed
488+-- value. However, the length of the result should be limited by the
489+-- first argument to 'unfoldrN'. This function is more efficient than
490+-- 'unfoldr' when the maximum length of the result is known and
491+-- correct, otherwise its performance is similar to 'unfoldr'.
492+unfoldrN :: Int64 -> (a -> Maybe (Char,a)) -> a -> Text
493+unfoldrN n f s = unstream (S.unfoldrN64 n f s)
494+{-# INLINE unfoldrN #-}
495+
471-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
496-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
472-- prefix of @t@ of length @n@, and whose second is the remainder of
497-- prefix of @t@ of length @n@, and whose second is the remainder of
473-- the string. It is equivalent to @('take' n t, 'drop' n t)@.
498-- the string. It is equivalent to @('take' n t, 'drop' n t)@.
tests/Properties.hs+15−7
@@ -198,14 +198,19 @@ prop_T_mapAccumR f z = L.mapAccumR f z `eqP` (second unpackT . T.mapAccumR f z
198prop_TL_mapAccumR f z = L.mapAccumR f z `eqP` (second unpackT . TL.mapAccumR f z)
198prop_TL_mapAccumR f z = L.mapAccumR f z `eqP` (second unpackT . TL.mapAccumR f z)
199 where types = f :: Int -> Char -> (Int,Char)
199 where types = f :: Int -> Char -> (Int,Char)
200
200
201−prop_T_replicate n = L.replicate n `eq` (unpackT . T.replicate n)
201+prop_T_replicate n = L.replicate n `eq` (unpackT . T.replicate n)
202−prop_T_unfoldr n = L.unfoldr f `eq` (unpackT . T.unfoldr f)
202+prop_TL_replicate n = L.replicate n `eq` (unpackT . TL.replicate n)
203− where f c | fromEnum c * 100 > n = Nothing
204− | otherwise = Just (c, succ c)
205
203
206−prop_T_unfoldrN n m = (L.take n . L.unfoldr f) `eq` (unpackT . T.unfoldrN n f)
204+unf :: Int -> Char -> Maybe (Char, Char)
207− where f c | fromEnum c * 100 > m = Nothing
205+unf n c | fromEnum c * 100 > n = Nothing
208− | otherwise = Just (c, succ c)
206+ | otherwise = Just (c, succ c)
207+
208+prop_T_unfoldr n = L.unfoldr (unf n) `eq` (unpackT . T.unfoldr (unf n))
209+prop_TL_unfoldr n = L.unfoldr (unf n) `eq` (unpackT . TL.unfoldr (unf n))
210+prop_T_unfoldrN n m = (L.take n . L.unfoldr (unf m)) `eq`
211+ (unpackT . T.unfoldrN n (unf m))
212+prop_TL_unfoldrN n m = (L.take n . L.unfoldr (unf m)) `eq`
213+ (unpackT . TL.unfoldrN (fromIntegral n) (unf m))
209
214
210unpack2 :: (Target t) => (t,t) -> (String,String)
215unpack2 :: (Target t) => (t,t) -> (String,String)
211unpack2 = unpackT *** unpackT
216unpack2 = unpackT *** unpackT
@@ -398,8 +403,11 @@ tests = [
398 ("prop_TL_mapAccumR", mytest prop_TL_mapAccumR),
403 ("prop_TL_mapAccumR", mytest prop_TL_mapAccumR),
399
404
400 ("prop_T_replicate", mytest prop_T_replicate),
405 ("prop_T_replicate", mytest prop_T_replicate),
406+ ("prop_TL_replicate", mytest prop_TL_replicate),
401 ("prop_T_unfoldr", mytest prop_T_unfoldr),
407 ("prop_T_unfoldr", mytest prop_T_unfoldr),
408+ ("prop_TL_unfoldr", mytest prop_TL_unfoldr),
402 ("prop_T_unfoldrN", mytest prop_T_unfoldrN),
409 ("prop_T_unfoldrN", mytest prop_T_unfoldrN),
410+ ("prop_TL_unfoldrN", mytest prop_TL_unfoldrN),
403
411
404 ("prop_T_take", mytest prop_T_take),
412 ("prop_T_take", mytest prop_T_take),
405 ("prop_T_drop", mytest prop_T_drop),
413 ("prop_T_drop", mytest prop_T_drop),