I am trying to pick up Haskell!

But I feel like my code is a bit painful to write and read.

Do you have any pointers on how to improve its readability / style?

main = do
contents <- fmap tail . fmap lines . readFile $"testInput" let input = map pair_to_tuple .(map (map read)) . map words$ contents :: [(Int,Int)]
let result = map (uncurry waffles) $input let decorated_result = ["Case #" ++ show i ++ ": " ++ show s | (i,s) <- zip [1..length result] result] writeFile "output.txt"$ unlines $decorated_result waffles row col = (row - 1)*(col - 1) pair_to_tuple [a,b] = (a,b)  This script reads a file whose first line is a title, then every line is a couple of numbers. Then it drops the first line, and processes every pair of numbers using the function waffles, then it writes it back to an output file. ## 1 Answer contents <- fmap tail . fmap lines . readFile$ "testInput"


can be written as

contents <- (tail . lines) <$> readFile "testInput"  Here we take advantage of the law fmap f . fmap g == fmap (f . g). <$> is an infix version of fmap. $ is extraneous here. let input = map pair_to_tuple .(map (map read)) . map words$ contents :: [(Int,Int)]


can be written as

let input = map (pair_to_tuple . (map read) . words) contents :: [(Int,Int)]


For lists map = fmap, so map f . map g == map (f . g) also holds.

In

let result = map (uncurry waffles) $input  the $ sign is also extraneous.

let decorated_result = ["Case #" ++ show i ++ ": " ++ show s | (i,s) <- zip [1..length result] result]


You can exploit Haskell's lazy evaluation and create infinite list to zip with:

let decorated_result = ["Case #" ++ show i ++ ": " ++ show s | (i,s) <- zip [1..] result]


Otherwise I'd say the code is fine.

• Thank you for your review! Why do you think I may have a typo on [1..length result]? The code certainly compiles and works as expected. – Jsevillamol Apr 25 '18 at 20:02
• @Jsevillamol Oh, right, stupid me. Updated my answer. – arrowd Apr 26 '18 at 4:17