diff --git a/Data/ByteString/Char8.hs b/Data/ByteString/Char8.hs index e7c1cf4fa..0977bb7d4 100644 --- a/Data/ByteString/Char8.hs +++ b/Data/ByteString/Char8.hs @@ -268,7 +268,7 @@ import Data.ByteString.Internal import Data.Char ( isSpace ) -- See bytestring #70 import GHC.Char (eqChar) -import qualified Data.List as List (intersperse) +import qualified Data.List as List (concatMap) import System.IO (Handle,stdout) import Foreign @@ -962,9 +962,7 @@ lines (BS x l) = go x l -- | 'unlines' is an inverse operation to 'lines'. It joins lines, -- after appending a terminating newline to each. unlines :: [ByteString] -> ByteString -unlines [] = empty -unlines ss = concat (List.intersperse nl ss) `append` nl -- half as much space - where nl = singleton '\n' +unlines = concat . List.concatMap (\x -> [x, singleton '\n']) -- | 'words' breaks a ByteString up into a list of words, which -- were delimited by Chars representing white space. diff --git a/Data/ByteString/Lazy/Char8.hs b/Data/ByteString/Lazy/Char8.hs index 164a189d0..e501ae442 100644 --- a/Data/ByteString/Lazy/Char8.hs +++ b/Data/ByteString/Lazy/Char8.hs @@ -888,9 +888,7 @@ lines (Chunk c0 cs0) = loop0 c0 cs0 -- | 'unlines' is an inverse operation to 'lines'. It joins lines, -- after appending a terminating newline to each. unlines :: [ByteString] -> ByteString -unlines [] = empty -unlines ss = concat (List.intersperse nl ss) `append` nl -- half as much space - where nl = singleton '\n' +unlines = concat . List.concatMap (\x -> [x, singleton '\n']) -- | 'words' breaks a ByteString up into a list of words, which -- were delimited by Chars representing white space. And diff --git a/bench/BenchAll.hs b/bench/BenchAll.hs index 0fc5f08b9..5a891fd1d 100644 --- a/bench/BenchAll.hs +++ b/bench/BenchAll.hs @@ -23,6 +23,7 @@ import Prelude hiding (words) import qualified Data.ByteString as S import qualified Data.ByteString.Char8 as S8 import qualified Data.ByteString.Lazy as L +import qualified Data.ByteString.Lazy.Char8 as L8 import Data.ByteString.Builder import Data.ByteString.Builder.Extra (byteStringCopy, @@ -468,6 +469,10 @@ main = do [ bench "map (+1) large" $ nf (S.map (+ 1)) largeTraversalInput , bench "map (+1) small" $ nf (S.map (+ 1)) smallTraversalInput ] + , bgroup "unlines" + [ bench "lazy" $ nf L8.unlines (map (L8.pack . show) intData) + , bench "strict" $ nf S8.unlines (map (S8.pack . show) intData) + ] , benchBoundsCheckFusion , benchCount , benchCSV diff --git a/tests/Properties.hs b/tests/Properties.hs index faf37a97e..af18c3a64 100644 --- a/tests/Properties.hs +++ b/tests/Properties.hs @@ -491,6 +491,7 @@ strictness_checks = D.take (D.length xs + 1) (D.scanl (+.) '\NUL' (explosiveTail (xs <> D.singleton '\SOH'))) === (D.pack . fmap (D.foldr (+.) '\NUL') . D.inits) xs , testProperty "scanl1 is lazy" $ \ xs -> D.length xs > 0 ==> let char1 +. char2 = toEnum (fromEnum char1 + fromEnum char2) in D.take (D.length xs) (D.scanl1 (+.) (explosiveTail (xs <> D.singleton '\SOH'))) === (D.pack . fmap (D.foldr1 (+.)) . tail . D.inits) xs + , testProperty "unlines is lazy" $ \ xs -> D.take (D.length xs + 1) (D.unlines (xs : error "Tail of this list is undefined!")) === xs `D.snoc` '\n' ] ]