on master help sign in
Implement and test lazy take

--HG-- extra : convert_revision : d6ce4a7fd959654fbd9c506002ef55992b9266b7

commit73f9b61f3fd5cb3461e2b5e96658ffa91ffe8ba1 authorBryan O'Sullivan <bos@serpentine.com> dateTue 3 Mar 2009, 08:04 (18 years ago) parentef61b49
3 files changed+27−2
Data/Text/Fusion/Common.hs+1−1 Data/Text/Lazy.hs+22−1 tests/Properties.hs+4
Data/Text/Fusion/Common.hs+1−1
@@ -530,7 +530,7 @@ unfoldrNI n f s0 | n < 0 = empty
530530-- | /O(n)/ take n, applied to a stream, returns the prefix of the
531531-- stream of length @n@, or the stream itself if @n@ is greater than the
532532-- length of the stream.
533−take :: Int -> Stream Char -> Stream Char
533+take :: Integral a => a -> Stream Char -> Stream Char
534534take n0 (Stream next0 s0 len) = Stream next (n0 :!: s0) len
535535 where
536536 {-# INLINE next #-}
Data/Text/Lazy.hs+22−1
@@ -94,7 +94,7 @@ module Data.Text.Lazy
9494 -- * Substrings
9595
9696 -- ** Breaking strings
97− -- , take
97+ , take
9898 -- , drop
9999 -- , takeWhile
100100 -- , dropWhile
@@ -493,6 +493,27 @@ unfoldrN :: Int64 -> (a -> Maybe (Char,a)) -> a -> Text
493493unfoldrN n f s = unstream (S.unfoldrN n f s)
494494{-# INLINE unfoldrN #-}
495495
496+-- | /O(n)/ 'take' @n@, applied to a 'Text', returns the prefix of the
497+-- 'Text' of length @n@, or the 'Text' itself if @n@ is greater than
498+-- the length of the Text. Subject to fusion.
499+take :: Int64 -> Text -> Text
500+take i _ | i <= 0 = Empty
501+take i t0 = take' i t0
502+ where take' 0 _ = Empty
503+ take' _ Empty = Empty
504+ take' n (Chunk t ts)
505+ | n < len = Chunk (T.take (fromIntegral n) t) Empty
506+ | otherwise = Chunk t (take' (n - len) ts)
507+ where len = fromIntegral (T.length t)
508+{-# INLINE [1] take #-}
509+
510+{-# RULES
511+"LAZY TEXT take -> fused" [~1] forall n t.
512+ take n t = unstream (S.take n (stream t))
513+"LAZY TEXT take -> unfused" [1] forall n t.
514+ unstream (S.take n (stream t)) = take n t
515+ #-}
516+
496517-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
497518-- prefix of @t@ of length @n@, and whose second is the remainder of
498519-- the string. It is equivalent to @('take' n t, 'drop' n t)@.
tests/Properties.hs+4
@@ -215,7 +215,9 @@ prop_TL_unfoldrN n m = (L.take n . L.unfoldr (unf m)) `eq`
215215unpack2 :: (Target t) => (t,t) -> (String,String)
216216unpack2 = unpackT *** unpackT
217217
218+prop_S_take n = L.take n `eqP` (unpackT . S.take n)
218219prop_T_take n = L.take n `eqP` (unpackT . T.take n)
220+prop_TL_take n = L.take n `eqP` (unpackT . TL.take (fromIntegral n))
219221prop_T_drop n = L.drop n `eqP` (unpackT . T.drop n)
220222prop_T_takeWhile p = L.takeWhile p `eqP` (unpackT . T.takeWhile p)
221223prop_T_takeWhileS p = L.takeWhile p `eqP` (unpackT . S.unstream . S.takeWhile p . S.stream)
@@ -408,7 +410,9 @@ tests = [
408410 ("prop_T_unfoldrN", mytest prop_T_unfoldrN),
409411 ("prop_TL_unfoldrN", mytest prop_TL_unfoldrN),
410412
413+ ("prop_S_take", mytest prop_S_take),
411414 ("prop_T_take", mytest prop_T_take),
415+ ("prop_TL_take", mytest prop_TL_take),
412416 ("prop_T_drop", mytest prop_T_drop),
413417 ("prop_T_takeWhile", mytest prop_T_takeWhile),
414418 ("prop_T_takeWhileS", mytest prop_T_takeWhileS),