@@ -45,7 +45,7 @@ module Data.Text.Lazy
4545 , append
4646 , uncons
4747 , head
48− -- , last
48+ , last
4949 -- , tail
5050 -- , init
5151 -- , null
@@ -151,6 +151,7 @@ import Prelude (Char, Bool(..), Functor(..), Int, Maybe(..), String,
151151 Read(..), Show(..),
152152 (&&), (||), (+), (-), (.), ($),
153153 not, return, otherwise)
154+import qualified Prelude as P
154155import Data.String (IsString(..))
155156import qualified Data.Text as T
156157import qualified Data.Text.Fusion as S
@@ -250,6 +251,22 @@ head :: Text -> Char
250251head t = S.head (stream t)
251252{-# INLINE head #-}
252253
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+
253270-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
254271-- prefix of @t@ of length @n@, and whose second is the remainder of
255272-- the string. It is equivalent to @('take' n t, 'drop' n t)@.
@@ -263,3 +280,6 @@ splitAt = loop
263280 | otherwise = let (ts',ts'') = loop (n - len) ts
264281 in (Chunk t ts', ts'')
265282 where len = T.length t
283+
284+emptyError :: String -> a
285+emptyError fun = P.error ("Data.Text.Lazy." ++ fun ++ ": empty input")