In today’s Programming Praxis exercise, we have to write a program to generate form letters. Let’s get started, shall we?
First, some imports:
import Control.Applicative ((*>), (<*>), (<$>)) import Text.CSV import Text.Parsec
The format for the message template is simple enough to do with a plain recursive algorithm, as I did initially, but in the end I decided to go with Parsec since it’s slightly cleaner.
fillWith :: String -> [String] -> String fillWith text vars = either show concat $ parse form "" text where form = many $ escape <|> count 1 anyChar escape = char '$' *> (string "$" <|> ((vars !!) . read <$> option "0" (many1 digit)))
Once we have the function to fill in the message template with a record, doing this for multiple records is pretty simple.
formLetters :: FilePath -> FilePath -> IO [String] formLetters schema vars = either (return . show) . map . fillWith <$> readFile schema <*> parseCSVFromFile vars
A quick test to see if everything is working properly:
main :: IO () main = mapM_ putStrLn =<< formLetters "schema.txt" "data.txt"
Yep. Now make sure never to use this code because nobody wants to see more form letters :)