(unlines . lines) . (unlines . lines) = (unlines . lines)
>>> lines "" -- empty input contains no lines []
>>> lines "\n" -- single empty line [""]
>>> lines "one" -- single unterminated line ["one"]
>>> lines "one\n" -- single non-empty line ["one"]
>>> lines "one\n\n" -- second line is empty ["one",""]
>>> lines "one\ntwo" -- second line is unterminated ["one","two"]
>>> lines "one\ntwo\n" -- two non-empty lines ["one","two"]
>>> lines "" -- empty input contains no lines [] >>> lines "\n" -- single empty line [""] >>> lines "one" -- single unterminated line ["one"] >>> lines "one\n" -- single non-empty line ["one"] >>> lines "one\n\n" -- second line is empty ["one",""] >>> lines "one\ntwo" -- second line is unterminated ["one","two"] >>> lines "one\ntwo\n" -- two non-empty lines ["one","two"]When the argument string is empty, or ends in a \n character, it can be recovered by passing the result of lines to the unlines function. Otherwise, unlines appends the missing terminating \n. This makes unlines . lines idempotent:
(unlines . lines) . (unlines . lines) = (unlines . lines)
ghci> is <- Streams.fromList ["Hello,\n world!"] >>= Streams.lines ghci> replicateM 3 (Streams.read is) [Just "Hello", Just ", world!", Nothing]Note that this may increase the chunk size if the input contains extremely long lines.
lines :: Text -> [Text]but it was given a more complex type to provide friendlier compile time errors.
>>> lines "" [] >>> lines "one line" ["one line"] >>> lines "line 1\nline 2" ["line 1","line 2"] >>> lines ("string line" :: String) ... ... 'lines' works with 'Text', not 'String'. Possible fixes: 1. Make sure OverloadedStrings extension is enabled. 2. Apply 'toText' to a single value. 3. Apply 'map toText' to the list value. ... >>> lines True ... ... 'lines' works with 'Text' But given: 'Bool' ...
>>> lines "" []
>>> lines "\n" [""]
>>> lines "one" ["one"]
>>> lines "one\n" ["one"]
>>> lines "one\n\n" ["one",""]
>>> lines "one\ntwo" ["one","two"]
>>> lines "one\ntwo\n" ["one","two"]Thus lines s contains at least as many elements as newlines in s.
> lines "hello\nworld" ["hello","world"]
lines = S.lines A.write
>>> Stream.fold Fold.toList $ Unicode.lines $ Stream.fromList "lines\nthis\nstring\n\n\n" [fromList "lines",fromList "this",fromList "string",fromList "",fromList ""]