Skip to content

Instantly share code, notes, and snippets.

@awonnacott
Last active May 2, 2017 23:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save awonnacott/acc7026ec5b16c860c872f12ae510393 to your computer and use it in GitHub Desktop.
Save awonnacott/acc7026ec5b16c860c872f12ae510393 to your computer and use it in GitHub Desktop.
Haskell version of formatter code using ByteStrings instead of [Chars]
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as C
main :: IO ()
main = B.getContents >>=
(mapM_ C.putStrLn) . map (C.intercalate (C.singleton ' ')) . (fmt 0 []) . (map C.words) . (C.split '\n')
fmt :: Int -> [B.ByteString] -> [[B.ByteString]] -> [[B.ByteString]]
-- Empty file
fmt _ [] [] = []
-- Should not be possible to enter this state
fmt _ part [] = (reverse part):[]
-- One-line file containing only whitespace
fmt _ [] ([]: []) = []
-- Base case for non-newline-terminated files
fmt _ part ([]: []) = (reverse part):[]
-- Base case for newline-termianted files
fmt _ part ([]:[]: []) = (reverse part):[]
-- Running out of words on a line with many following blank lines
fmt _ part ([]:[]:[]:lines) = (reverse part):(fmt 0 [] ([]:[]:lines))
-- Print two blank lines on the second-to-last blank line
fmt _ part ([]:[]:lines) = (reverse part):[]:(fmt 0 [] lines)
-- If I run out of words on a line, go on to the next one
fmt i part ([]:lines) = fmt i part lines
-- The core recursion which builds stacks of words and yields them as lines
fmt i part ((word:words):lines) =
if (C.length word + i + length part - 1) > 60 then
if i == 0 then
(word:[]):(fmt 0 [] (words:lines))
else
(reverse part):(fmt (C.length word) (word:[]) (words:lines))
else
fmt (C.length word + i) (word:part) (words:lines)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment