on master help sign in
Implement and test lazy last
d581176Bryan O'Sullivan
Data/Text/Lazy.hs+21−1
@@ -45,7 +45,7 @@ module Data.Text.Lazy
45 , append
45 , append
46 , uncons
46 , uncons
47 , head
47 , head
48− -- , last
48+ , last
49 -- , tail
49 -- , tail
50 -- , init
50 -- , init
51 -- , null
51 -- , null
@@ -151,6 +151,7 @@ import Prelude (Char, Bool(..), Functor(..), Int, Maybe(..), String,
151 Read(..), Show(..),
151 Read(..), Show(..),
152 (&&), (||), (+), (-), (.), ($),
152 (&&), (||), (+), (-), (.), ($),
153 not, return, otherwise)
153 not, return, otherwise)
154+import qualified Prelude as P
154import Data.String (IsString(..))
155import Data.String (IsString(..))
155import qualified Data.Text as T
156import qualified Data.Text as T
156import qualified Data.Text.Fusion as S
157import qualified Data.Text.Fusion as S
@@ -250,6 +251,22 @@ head :: Text -> Char
250head t = S.head (stream t)
251head t = S.head (stream t)
251{-# INLINE head #-}
252{-# INLINE head #-}
252
253
254+-- | /O(1)/ Returns the last character of a 'Text', which must be
255+-- non-empty. Subject to array fusion.
256+last :: Text -> Char
257+last Empty = emptyError "last"
258+last (Chunk t ts) = go t ts
259+ where go _ (Chunk t' ts') = go t' ts'
260+ go t Empty = T.last t
261+{-# INLINE [1] last #-}
262+
263+{-# RULES
264+"LAZY TEXT last -> fused" [~1] forall t.
265+ last t = S.last (stream t)
266+"LAZY TEXT last -> unfused" [1] forall t.
267+ S.last (stream t) = last t
268+ #-}
269+
253-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
270-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
254-- prefix of @t@ of length @n@, and whose second is the remainder of
271-- prefix of @t@ of length @n@, and whose second is the remainder of
255-- the string. It is equivalent to @('take' n t, 'drop' n t)@.
272-- the string. It is equivalent to @('take' n t, 'drop' n t)@.
@@ -263,3 +280,6 @@ splitAt = loop
263 | otherwise = let (ts',ts'') = loop (n - len) ts
280 | otherwise = let (ts',ts'') = loop (n - len) ts
264 in (Chunk t ts', ts'')
281 in (Chunk t ts', ts'')
265 where len = T.length t
282 where len = T.length t
283+
284+emptyError :: String -> a
285+emptyError fun = P.error ("Data.Text.Lazy." ++ fun ++ ": empty input")
tests/Properties.hs+4−2
@@ -124,8 +124,9 @@ prop_TL_uncons s = uncons `eqP` (fmap (second unpackT) . TL.uncons)
124prop_S_head = head `eqEP` S.head
124prop_S_head = head `eqEP` S.head
125prop_T_head = head `eqEP` T.head
125prop_T_head = head `eqEP` T.head
126prop_TL_head = head `eqEP` TL.head
126prop_TL_head = head `eqEP` TL.head
127+prop_S_last = last `eqEP` S.last
127prop_T_last = last `eqEP` T.last
128prop_T_last = last `eqEP` T.last
128−prop_T_lastS = last `eqEP` (S.last . S.stream)
129+prop_TL_last = last `eqEP` TL.last
129prop_T_tail = tail `eqEP` (unpackT . T.tail)
130prop_T_tail = tail `eqEP` (unpackT . T.tail)
130prop_T_tailS = tail `eqEP` (unpackT . S.unstream . S.tail . S.stream)
131prop_T_tailS = tail `eqEP` (unpackT . S.unstream . S.tail . S.stream)
131prop_T_init = init `eqEP` (unpackT . T.init)
132prop_T_init = init `eqEP` (unpackT . T.init)
@@ -300,8 +301,9 @@ tests = [
300 ("prop_S_head", mytest prop_S_head),
301 ("prop_S_head", mytest prop_S_head),
301 ("prop_T_head", mytest prop_T_head),
302 ("prop_T_head", mytest prop_T_head),
302 ("prop_TL_head", mytest prop_TL_head),
303 ("prop_TL_head", mytest prop_TL_head),
304+ ("prop_S_last", mytest prop_S_last),
303 ("prop_T_last", mytest prop_T_last),
305 ("prop_T_last", mytest prop_T_last),
304− ("prop_T_lastS", mytest prop_T_lastS),
306+ ("prop_TL_last", mytest prop_TL_last),
305 ("prop_T_tail", mytest prop_T_tail),
307 ("prop_T_tail", mytest prop_T_tail),
306 ("prop_T_tailS", mytest prop_T_tailS),
308 ("prop_T_tailS", mytest prop_T_tailS),
307 ("prop_T_init", mytest prop_T_init),
309 ("prop_T_init", mytest prop_T_init),