Infinite House of Pancakes in Haskell In order to learn haskell, I wrote a solver for the Infinite House of Pancakes problem. 

-- Solve the 'Infinite House of Pancakes' problem.
-- https://code.google.com/codejam/contest/6224486/dashboard#s=p1

import Text.Printf
import Control.Monad

-- Generic solver code

readInt :: IO Int
readInt = readLn

readIntList :: IO [Int]
readIntList = getLine &gt;&gt;= return . map read . words

main :: IO [()]
main = do
  n &lt;- readInt
  forM [1..n] (\i -&gt;
    parse &gt;&gt;= putStr . printf "Case #%d: %d\n" i . solve)

-- Problem-specific code

parse :: IO [Int]
parse = getLine &gt;&gt; readIntList

cost :: Int -&gt; Int -&gt; Int
cost l n = if r == 0 then q - 1 else q where (q, r) = n `quotRem` l

test :: Int -&gt; [Int] -&gt; Int
test l = (+l) . sum . map (cost l)

solve :: [Int] -&gt; Int
solve s = minimum . map (\l -&gt; test l s) $ [1 .. maximum s]


I used this python solution as a reference, which is based on the  following problem analysis. I tested  my program using those input and output files, and it seems to work fine:

$ stack ghc pancake.hs -- -O2
$ \time -f "%e s" ./pancake &lt; B-large-practice.in | diff - B-large-practice.out
0.28 s


I'm looking for comments about the following points:


coding style
performance (currently runs in 0.28 seconds using -O2, against 5.5 seconds for python 3)
bind operators vs do syntax (I used both  here, but it was mostly for educational purposes)
tools and ecosystem (code analysis, better compilation flags, etc.)




EDIT - Thanks to @Gurkenglas answer, I've been able to improve this program quite a lot. Here's a link to the corresponding gist.
I'll refactor so every line tells the reader something about the program.

{-# LANGUAGE ScopedTypeVariables #-}
import Text.Printf
import Control.Monad
import Data.List.Split (splitPlaces)
import Safe (headNote)

main :: IO ()
main = interact                                                                -- no side effects
  $ (\f -&gt; unlines . zipWith f [1..] . subList [2,4..] . lines)                -- embarassingly parallel
  $ (\solve (i :: Int) -&gt; printf "Case #%d: %d" i . solve . map read . words)  -- mere math
  $ (\cost (s :: [Int]) -&gt; minimum [cost l s | l &lt;- [1 .. maximum s]])         -- brute optimization
  $ \l -&gt; (+l) . sum . map ((`div` l) . subtract 1)

-- This gets a name because we ought to be importing it from a library.
subList :: [Int] -&gt; [a] -&gt; [a]
subList is = map (headNote "subList: index list not strictly ascending")
  . drop 1 . splitPlaces (zipWith (-) is $ 0:is)