on master help sign in
Implement and test unfolds

--HG-- extra : convert_revision : c08d517061a1d725e92fe58ab9b15aee59483bbb

commit82875b9f417f0b796a880b821e26c1ad4b90c8cf authorBryan O'Sullivan <bos@serpentine.com> dateTue 3 Mar 2009, 06:53 (18 years ago) parent6cd4112
3 files changed+67−15
Data/Text/Fusion.hs+24−5 Data/Text/Lazy.hs+28−3 tests/Properties.hs+15−7
Data/Text/Fusion.hs+24−5
@@ -75,6 +75,7 @@ module Data.Text.Fusion
7575 , replicate
7676 , unfoldr
7777 , unfoldrN
78+ , unfoldrN64
7879
7980 -- * Substrings
8081 -- ** Breaking strings
@@ -104,8 +105,8 @@ module Data.Text.Fusion
104105 , zipWith
105106 ) where
106107
107−import Prelude (Bool(..), Char, Either(..), Eq(..), Maybe(..), Monad(..),
108− Num(..), Ord(..), String, ($), (++), (.), (&&),
108+import Prelude (Bool(..), Char, Either(..), Eq(..), Integral, Maybe(..),
109+ Monad(..), Num(..), Ord(..), String, ($), (++), (.), (&&),
109110 fromIntegral, otherwise)
110111import qualified Data.List as L
111112import GHC.Exts (Int(..), (+#))
@@ -641,15 +642,33 @@ unfoldr f s0 = Stream next s0 1
641642-- value. However, the length of the result is limited by the
642643-- first argument to 'unfoldrN'. This function is more efficient than
643644-- 'unfoldr' when the length of the result is known.
644−unfoldrN :: Int -> (a -> Maybe (Char,a)) -> a -> Stream Char
645−unfoldrN n f s0 | n < 0 = empty
646− | otherwise = Stream next (0 :!: s0) (n*2)
645+unfoldrI :: Integral a => a -> (b -> Maybe (Char,b)) -> b -> Stream Char
646+unfoldrI n f s0 | n < 0 = empty
647+ | otherwise = Stream next (0 :!: s0) (fromIntegral (n*2))
647648 where
648649 {-# INLINE next #-}
649650 next (z :!: s) = case f s of
650651 Nothing -> Done
651652 Just (w, s') | z >= n -> Done
652653 | 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+
653672-------------------------------------------------------------------------------
654673-- * Substreams
655674
Data/Text/Lazy.hs+28−3
@@ -87,9 +87,9 @@ module Data.Text.Lazy
8787 , mapAccumR
8888
8989 -- ** Generation and unfolding
90− -- , replicate
91− -- , unfoldr
92− -- , unfoldrN
90+ , replicate
91+ , unfoldr
92+ , unfoldrN
9393
9494 -- * Substrings
9595
@@ -468,6 +468,31 @@ mapAccumR f s t = case uncons t of
468468 where (s'',y ) = f s' x
469469 (s', ys) = mapAccumR f s xs
470470
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+
471496-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
472497-- prefix of @t@ of length @n@, and whose second is the remainder of
473498-- 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
198198prop_TL_mapAccumR f z = L.mapAccumR f z `eqP` (second unpackT . TL.mapAccumR f z)
199199 where types = f :: Int -> Char -> (Int,Char)
200200
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)
203− where f c | fromEnum c * 100 > n = Nothing
204− | otherwise = Just (c, succ c)
201+prop_T_replicate n = L.replicate n `eq` (unpackT . T.replicate n)
202+prop_TL_replicate n = L.replicate n `eq` (unpackT . TL.replicate n)
205203
206−prop_T_unfoldrN n m = (L.take n . L.unfoldr f) `eq` (unpackT . T.unfoldrN n f)
207− where f c | fromEnum c * 100 > m = Nothing
208− | otherwise = Just (c, succ c)
204+unf :: Int -> Char -> Maybe (Char, Char)
205+unf n c | fromEnum c * 100 > n = Nothing
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))
209214
210215unpack2 :: (Target t) => (t,t) -> (String,String)
211216unpack2 = unpackT *** unpackT
@@ -398,8 +403,11 @@ tests = [
398403 ("prop_TL_mapAccumR", mytest prop_TL_mapAccumR),
399404
400405 ("prop_T_replicate", mytest prop_T_replicate),
406+ ("prop_TL_replicate", mytest prop_TL_replicate),
401407 ("prop_T_unfoldr", mytest prop_T_unfoldr),
408+ ("prop_TL_unfoldr", mytest prop_TL_unfoldr),
402409 ("prop_T_unfoldrN", mytest prop_T_unfoldrN),
410+ ("prop_TL_unfoldrN", mytest prop_TL_unfoldrN),
403411
404412 ("prop_T_take", mytest prop_T_take),
405413 ("prop_T_drop", mytest prop_T_drop),